summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING340
-rw-r--r--HISTORY7
-rw-r--r--Makefile176
-rw-r--r--README102
-rw-r--r--config.c76
-rw-r--r--config.h53
-rw-r--r--designer.c309
-rw-r--r--designer.h49
-rw-r--r--displaychannel.c193
-rw-r--r--displaychannel.h32
-rw-r--r--displaymenu.c233
-rw-r--r--displaymenu.h48
-rw-r--r--displaymessage.c43
-rw-r--r--displaymessage.h22
-rw-r--r--displayreplay.c131
-rw-r--r--displayreplay.h34
-rw-r--r--displaytracks.c58
-rw-r--r--displaytracks.h27
-rw-r--r--displayvolume.c43
-rw-r--r--displayvolume.h21
-rw-r--r--fonts/VDROpenSans/Apache License.txt201
-rw-r--r--fonts/VDROpenSans/VDROpenSans-Bold.ttfbin0 -> 125932 bytes
-rw-r--r--fonts/VDROpenSans/VDROpenSans-BoldItalic.ttfbin0 -> 114584 bytes
-rw-r--r--fonts/VDROpenSans/VDROpenSans-ExtraBold.ttfbin0 -> 123960 bytes
-rw-r--r--fonts/VDROpenSans/VDROpenSans-ExtraBoldItalic.ttfbin0 -> 114768 bytes
-rw-r--r--fonts/VDROpenSans/VDROpenSans-Italic.ttfbin0 -> 114100 bytes
-rw-r--r--fonts/VDROpenSans/VDROpenSans-Light.ttfbin0 -> 123772 bytes
-rw-r--r--fonts/VDROpenSans/VDROpenSans-LightItalic.ttfbin0 -> 114484 bytes
-rw-r--r--fonts/VDROpenSans/VDROpenSans-Regular.ttfbin0 -> 118664 bytes
-rw-r--r--fonts/VDROpenSans/VDROpenSans-Semibold.ttfbin0 -> 122672 bytes
-rw-r--r--fonts/VDROpenSans/VDROpenSans-SemiboldItalic.ttfbin0 -> 114192 bytes
-rw-r--r--libcore/fontmanager.c174
-rw-r--r--libcore/fontmanager.h35
-rw-r--r--libcore/helpers.c155
-rw-r--r--libcore/helpers.h35
-rw-r--r--libcore/imagecache.c389
-rw-r--r--libcore/imagecache.h53
-rw-r--r--libcore/imageloader.c56
-rw-r--r--libcore/imageloader.h23
-rw-r--r--libcore/imagemagickwrapper.c162
-rw-r--r--libcore/imagemagickwrapper.h28
-rw-r--r--libcore/imagescaler.c149
-rw-r--r--libcore/imagescaler.h97
-rw-r--r--libcore/pixmapcontainer.c477
-rw-r--r--libcore/pixmapcontainer.h73
-rw-r--r--libcore/timers.c84
-rw-r--r--libcore/timers.h20
-rw-r--r--libtemplate/globals.c98
-rw-r--r--libtemplate/globals.h38
-rw-r--r--libtemplate/parameter.c394
-rw-r--r--libtemplate/parameter.h138
-rw-r--r--libtemplate/template.c273
-rw-r--r--libtemplate/template.h57
-rw-r--r--libtemplate/templatefunction.c1474
-rw-r--r--libtemplate/templatefunction.h211
-rw-r--r--libtemplate/templateloopfunction.c208
-rw-r--r--libtemplate/templateloopfunction.h33
-rw-r--r--libtemplate/templatepixmap.c473
-rw-r--r--libtemplate/templatepixmap.h82
-rw-r--r--libtemplate/templateview.c1567
-rw-r--r--libtemplate/templateview.h198
-rw-r--r--libtemplate/templateviewelement.c128
-rw-r--r--libtemplate/templateviewelement.h99
-rw-r--r--libtemplate/templateviewlist.c138
-rw-r--r--libtemplate/templateviewlist.h49
-rw-r--r--libtemplate/templateviewtab.c38
-rw-r--r--libtemplate/templateviewtab.h31
-rw-r--r--libtemplate/xmlparser.c728
-rw-r--r--libtemplate/xmlparser.h56
-rw-r--r--services/epgsearch.h167
-rw-r--r--services/remotetimers.h141
-rw-r--r--services/scraper2vdr.h214
-rw-r--r--setup.c73
-rw-r--r--setup.h16
-rw-r--r--skindesigner.c165
-rw-r--r--skins/default/graphics/icons/ico_ac3.pngbin0 -> 2684 bytes
-rw-r--r--skins/default/graphics/icons/ico_activetimer.pngbin0 -> 1731 bytes
-rw-r--r--skins/default/graphics/icons/ico_channelsep.pngbin0 -> 958 bytes
-rw-r--r--skins/default/graphics/icons/ico_crypt_off.pngbin0 -> 386 bytes
-rw-r--r--skins/default/graphics/icons/ico_crypt_on.pngbin0 -> 369 bytes
-rw-r--r--skins/default/graphics/icons/ico_cutted.pngbin0 -> 2007 bytes
-rw-r--r--skins/default/graphics/icons/ico_discusage.pngbin0 -> 4404 bytes
-rw-r--r--skins/default/graphics/icons/ico_dolby_off.pngbin0 -> 458 bytes
-rw-r--r--skins/default/graphics/icons/ico_dolby_on.pngbin0 -> 413 bytes
-rw-r--r--skins/default/graphics/icons/ico_ff.pngbin0 -> 4572 bytes
-rw-r--r--skins/default/graphics/icons/ico_ff_1x.pngbin0 -> 5264 bytes
-rw-r--r--skins/default/graphics/icons/ico_ff_2x.pngbin0 -> 5564 bytes
-rw-r--r--skins/default/graphics/icons/ico_ff_3x.pngbin0 -> 5639 bytes
-rw-r--r--skins/default/graphics/icons/ico_ff_off.pngbin0 -> 3265 bytes
-rw-r--r--skins/default/graphics/icons/ico_hd_off.pngbin0 -> 1603 bytes
-rw-r--r--skins/default/graphics/icons/ico_hd_on.pngbin0 -> 1904 bytes
-rw-r--r--skins/default/graphics/icons/ico_line_off.pngbin0 -> 147 bytes
-rw-r--r--skins/default/graphics/icons/ico_line_on.pngbin0 -> 958 bytes
-rw-r--r--skins/default/graphics/icons/ico_mute.pngbin0 -> 3075 bytes
-rw-r--r--skins/default/graphics/icons/ico_pause.pngbin0 -> 1558 bytes
-rw-r--r--skins/default/graphics/icons/ico_pause_off.pngbin0 -> 1191 bytes
-rw-r--r--skins/default/graphics/icons/ico_play.pngbin0 -> 3481 bytes
-rw-r--r--skins/default/graphics/icons/ico_play_off.pngbin0 -> 2505 bytes
-rw-r--r--skins/default/graphics/icons/ico_rec_off.pngbin0 -> 788 bytes
-rw-r--r--skins/default/graphics/icons/ico_rec_on.pngbin0 -> 1111 bytes
-rw-r--r--skins/default/graphics/icons/ico_recfolder.pngbin0 -> 2423 bytes
-rw-r--r--skins/default/graphics/icons/ico_recnew.pngbin0 -> 2815 bytes
-rw-r--r--skins/default/graphics/icons/ico_rew.pngbin0 -> 4515 bytes
-rw-r--r--skins/default/graphics/icons/ico_rew_1x.pngbin0 -> 5201 bytes
-rw-r--r--skins/default/graphics/icons/ico_rew_2x.pngbin0 -> 5508 bytes
-rw-r--r--skins/default/graphics/icons/ico_rew_3x.pngbin0 -> 5582 bytes
-rw-r--r--skins/default/graphics/icons/ico_rew_off.pngbin0 -> 3373 bytes
-rw-r--r--skins/default/graphics/icons/ico_stereo.pngbin0 -> 4433 bytes
-rw-r--r--skins/default/graphics/icons/ico_timer_active.pngbin0 -> 3297 bytes
-rw-r--r--skins/default/graphics/icons/ico_timer_inactive.pngbin0 -> 1527 bytes
-rw-r--r--skins/default/graphics/icons/ico_timer_recording.pngbin0 -> 531 bytes
-rw-r--r--skins/default/graphics/icons/ico_txt_off.pngbin0 -> 346 bytes
-rw-r--r--skins/default/graphics/icons/ico_txt_on.pngbin0 -> 349 bytes
-rw-r--r--skins/default/graphics/icons/ico_volume.pngbin0 -> 7443 bytes
-rw-r--r--skins/default/graphics/icons/ico_widescreen_off.pngbin0 -> 861 bytes
-rw-r--r--skins/default/graphics/icons/ico_widescreen_on.pngbin0 -> 1072 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Applikationen.pngbin0 -> 2073 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Audio.pngbin0 -> 2674 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Aufnahmen-Liste aktualisieren.pngbin0 -> 3550 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Dienstprogramme.pngbin0 -> 1581 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/FireFox.pngbin0 -> 3359 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Info.pngbin0 -> 2138 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Internet.pngbin0 -> 3801 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Medien.pngbin0 -> 3009 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Rechner neu starten.pngbin0 -> 2886 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Remote wakeup.pngbin0 -> 859 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Spiele.pngbin0 -> 2993 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/System herunterfahren.pngbin0 -> 2713 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/System.pngbin0 -> 3227 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Tools.pngbin0 -> 2355 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Tunderbird.pngbin0 -> 3544 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/USB Massenspeicher sicher entfernen.pngbin0 -> 2019 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/VDR neu starten.pngbin0 -> 2577 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Video.pngbin0 -> 2276 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Web.pngbin0 -> 3930 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/XBMC.pngbin0 -> 3336 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/Xterm.pngbin0 -> 1575 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/audiovideo.pngbin0 -> 2765 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/markad_status.pngbin0 -> 2865 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/schneiden_abbrechen.pngbin0 -> 3420 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/tux.pngbin0 -> 3852 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/usb.pngbin0 -> 1438 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/vdrlogo.pngbin0 -> 12796 bytes
-rw-r--r--skins/default/graphics/menuicons/customicons/yaicon_blue.pngbin0 -> 1931 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/admin.pngbin0 -> 2355 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/arghdirector.pngbin0 -> 1824 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/autostart.pngbin0 -> 3320 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/avahi4vdr.pngbin0 -> 3734 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/avards.pngbin0 -> 665 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/block.pngbin0 -> 1341 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/burn.pngbin0 -> 4233 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/cdplayer.pngbin0 -> 2258 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/chanman.pngbin0 -> 3224 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/check.pngbin0 -> 2141 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/conflictcheckonly.pngbin0 -> 3050 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/ddci.pngbin0 -> 2876 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/devstatus.pngbin0 -> 3159 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/dummydevice.pngbin0 -> 2035 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/duplicates.pngbin0 -> 2485 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/dvbapi.pngbin0 -> 2869 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/dvbhddevice.pngbin0 -> 3175 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/dvbsddevice.pngbin0 -> 3588 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/dynamite.pngbin0 -> 3973 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/eepg.pngbin0 -> 3590 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/epg2vdr.pngbin0 -> 4051 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/epgsearch.pngbin0 -> 3228 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/epgsearchonly.pngbin0 -> 2983 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/epgsync.pngbin0 -> 3518 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/externalplayer.pngbin0 -> 2449 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/extrecmenu.pngbin0 -> 2323 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/favorites.pngbin0 -> 1375 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/femon.pngbin0 -> 3331 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/fepg.pngbin0 -> 2406 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/filebrowser.pngbin0 -> 1463 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/fritzbox.pngbin0 -> 1931 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/graphlcd.pngbin0 -> 1421 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/graphtft.pngbin0 -> 1421 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/image.pngbin0 -> 2559 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/imonlcd.pngbin0 -> 1421 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/iptv.pngbin0 -> 2774 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/lcdproc.pngbin0 -> 1421 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/mailbox.pngbin0 -> 1904 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/makemkv.pngbin0 -> 1941 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/markad.pngbin0 -> 2865 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/mlist.pngbin0 -> 2505 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/music.pngbin0 -> 2674 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/noepg.pngbin0 -> 3355 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/nordlichtsepg.pngbin0 -> 2643 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/osdteletext.pngbin0 -> 1591 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/peer.pngbin0 -> 4175 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/play.pngbin0 -> 1059 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/pvrinput.pngbin0 -> 1976 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/quickepgsearch.pngbin0 -> 4781 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/radio.pngbin0 -> 2016 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/remote.pngbin0 -> 3807 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/remotetimers.pngbin0 -> 4372 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/rssreader.pngbin0 -> 2620 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/sc.pngbin0 -> 2208 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/scraper2vdr.pngbin0 -> 2726 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/screenshot.pngbin0 -> 2526 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/seduatmo.pngbin0 -> 2024 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/skyselectfeeds.pngbin0 -> 2852 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/sleeptimer.pngbin0 -> 4694 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/softhddevice.pngbin0 -> 2410 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/streamdev-server.pngbin0 -> 2821 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/systeminfo.pngbin0 -> 1709 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/targavfd.pngbin0 -> 1421 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/trayopenng.pngbin0 -> 1077 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/tvguide.pngbin0 -> 2129 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/tvm2vdr.pngbin0 -> 2622 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/tvscraper.pngbin0 -> 2726 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/undelete.pngbin0 -> 2947 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/weatherng.pngbin0 -> 1726 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/xmltv2vdr.pngbin0 -> 2985 bytes
-rw-r--r--skins/default/graphics/menuicons/pluginicons/yaepghg.pngbin0 -> 2129 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/CAM.pngbin0 -> 1619 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/Channels.pngbin0 -> 3561 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/Commands.pngbin0 -> 2428 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/DVB.pngbin0 -> 2758 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/EPG.pngbin0 -> 2874 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/LNB.pngbin0 -> 3739 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/Miscellaneous.pngbin0 -> 1576 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/OSD.pngbin0 -> 1577 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/Plugins.pngbin0 -> 2230 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/Recording.pngbin0 -> 1115 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/Recordings.pngbin0 -> 3640 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/Replay.pngbin0 -> 1059 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/Restart.pngbin0 -> 2577 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/Schedule.pngbin0 -> 2056 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/Setup.pngbin0 -> 3179 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/StopRecording.pngbin0 -> 547 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/StopReplay.pngbin0 -> 1595 bytes
-rw-r--r--skins/default/graphics/menuicons/standardicons/Timers.pngbin0 -> 4113 bytes
-rw-r--r--skins/default/xmlfiles/displayaudiotracks.xml46
-rw-r--r--skins/default/xmlfiles/displaychannel.xml213
-rw-r--r--skins/default/xmlfiles/displaymenu.xml155
-rw-r--r--skins/default/xmlfiles/displaymenuchannels.xml117
-rw-r--r--skins/default/xmlfiles/displaymenudefault.xml184
-rw-r--r--skins/default/xmlfiles/displaymenudetailepg.xml335
-rw-r--r--skins/default/xmlfiles/displaymenudetailrecording.xml310
-rw-r--r--skins/default/xmlfiles/displaymenudetailtext.xml99
-rw-r--r--skins/default/xmlfiles/displaymenumain.xml276
-rw-r--r--skins/default/xmlfiles/displaymenurecordings.xml85
-rw-r--r--skins/default/xmlfiles/displaymenuschedules.xml179
-rw-r--r--skins/default/xmlfiles/displaymenusetup.xml107
-rw-r--r--skins/default/xmlfiles/displaymenutimers.xml90
-rw-r--r--skins/default/xmlfiles/displaymessage.xml27
-rw-r--r--skins/default/xmlfiles/displayreplay.xml231
-rw-r--r--skins/default/xmlfiles/displayvolume.xml29
-rw-r--r--skins/default/xmlfiles/globals.xml210
-rw-r--r--skins/dtd/displayaudiotracks.dtd42
-rw-r--r--skins/dtd/displaychannel.dtd86
-rw-r--r--skins/dtd/displaymenu.dtd251
-rw-r--r--skins/dtd/displaymessage.dtd28
-rw-r--r--skins/dtd/displayreplay.dtd91
-rw-r--r--skins/dtd/displayvolume.dtd28
-rw-r--r--skins/dtd/functions.dtd131
-rw-r--r--skins/dtd/globals.dtd29
-rw-r--r--skins/nopacity/graphics/icons/ico_ac3.pngbin0 -> 2684 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_activetimer.pngbin0 -> 1731 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_arrow_left_channelsep.pngbin0 -> 11625 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_arrow_right_channelsep.pngbin0 -> 10951 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_channelsep.pngbin0 -> 958 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_cutted.pngbin0 -> 2007 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_daydelimiter.pngbin0 -> 2785 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_discusage.pngbin0 -> 4404 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_dolbyoff.pngbin0 -> 1791 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_dolbyon.pngbin0 -> 1792 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_encrypted.pngbin0 -> 957 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_ff.pngbin0 -> 11503 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_ff_1x.pngbin0 -> 13093 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_ff_2x.pngbin0 -> 13094 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_ff_3x.pngbin0 -> 13010 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_ff_off.pngbin0 -> 12656 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_fta.pngbin0 -> 1641 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_hd1080i.pngbin0 -> 1095 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_hd720p.pngbin0 -> 2299 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_mute.pngbin0 -> 3075 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_pause.pngbin0 -> 4959 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_pause_off.pngbin0 -> 6329 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_play.pngbin0 -> 10550 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_play_off.pngbin0 -> 10871 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_recfolder.pngbin0 -> 2423 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_recnew.pngbin0 -> 2815 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_recoff.pngbin0 -> 2543 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_recon.pngbin0 -> 2776 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_rew.pngbin0 -> 12275 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_rew_1x.pngbin0 -> 13588 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_rew_2x.pngbin0 -> 13660 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_rew_3x.pngbin0 -> 13970 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_rew_off.pngbin0 -> 13211 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_sd576i.pngbin0 -> 2363 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_stereo.pngbin0 -> 4433 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_stereooff.pngbin0 -> 1944 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_stereoon.pngbin0 -> 1609 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_timer_active.pngbin0 -> 3297 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_timer_inactive.pngbin0 -> 1527 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_timer_recording.pngbin0 -> 531 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_txtoff.pngbin0 -> 1216 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_txton.pngbin0 -> 1214 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_vdrlogo.pngbin0 -> 11135 bytes
-rw-r--r--skins/nopacity/graphics/icons/ico_volume.pngbin0 -> 7443 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Applikationen.pngbin0 -> 2073 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Audio.pngbin0 -> 2674 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Aufnahmen-Liste aktualisieren.pngbin0 -> 3550 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Dienstprogramme.pngbin0 -> 1581 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/FireFox.pngbin0 -> 3359 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Info.pngbin0 -> 2138 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Internet.pngbin0 -> 3801 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Medien.pngbin0 -> 3009 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Rechner neu starten.pngbin0 -> 2886 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Remote wakeup.pngbin0 -> 859 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Spiele.pngbin0 -> 2993 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/System herunterfahren.pngbin0 -> 2713 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/System.pngbin0 -> 3227 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Tools.pngbin0 -> 2355 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Tunderbird.pngbin0 -> 3544 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/USB Massenspeicher sicher entfernen.pngbin0 -> 2019 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/VDR neu starten.pngbin0 -> 2577 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Video.pngbin0 -> 2276 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Web.pngbin0 -> 3930 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/XBMC.pngbin0 -> 3336 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/Xterm.pngbin0 -> 1575 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/audiovideo.pngbin0 -> 2765 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/markad_status.pngbin0 -> 2865 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/schneiden_abbrechen.pngbin0 -> 3420 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/tux.pngbin0 -> 3852 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/usb.pngbin0 -> 1438 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/vdrlogo.pngbin0 -> 12796 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/customicons/yaicon_blue.pngbin0 -> 1931 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/admin.pngbin0 -> 2355 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/arghdirector.pngbin0 -> 1824 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/autostart.pngbin0 -> 3320 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/avahi4vdr.pngbin0 -> 3734 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/avards.pngbin0 -> 665 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/block.pngbin0 -> 1341 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/burn.pngbin0 -> 4233 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/cdplayer.pngbin0 -> 2258 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/chanman.pngbin0 -> 3224 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/check.pngbin0 -> 2141 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/conflictcheckonly.pngbin0 -> 3050 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/ddci.pngbin0 -> 2876 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/devstatus.pngbin0 -> 3159 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/dummydevice.pngbin0 -> 2035 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/duplicates.pngbin0 -> 2485 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/dvbapi.pngbin0 -> 2869 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/dvbhddevice.pngbin0 -> 3175 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/dvbsddevice.pngbin0 -> 3588 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/dynamite.pngbin0 -> 3973 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/eepg.pngbin0 -> 3590 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/epg2vdr.pngbin0 -> 4051 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/epgsearch.pngbin0 -> 3228 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/epgsearchonly.pngbin0 -> 2983 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/epgsync.pngbin0 -> 3518 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/externalplayer.pngbin0 -> 2449 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/extrecmenu.pngbin0 -> 2323 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/favorites.pngbin0 -> 1375 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/femon.pngbin0 -> 3331 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/fepg.pngbin0 -> 2406 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/filebrowser.pngbin0 -> 1463 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/fritzbox.pngbin0 -> 1931 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/graphlcd.pngbin0 -> 1421 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/graphtft.pngbin0 -> 1421 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/image.pngbin0 -> 2559 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/imonlcd.pngbin0 -> 1421 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/iptv.pngbin0 -> 2774 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/lcdproc.pngbin0 -> 1421 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/mailbox.pngbin0 -> 1904 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/makemkv.pngbin0 -> 1941 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/markad.pngbin0 -> 2865 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/mlist.pngbin0 -> 2505 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/music.pngbin0 -> 2674 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/noepg.pngbin0 -> 3355 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/nordlichtsepg.pngbin0 -> 2643 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/osdteletext.pngbin0 -> 1591 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/peer.pngbin0 -> 4175 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/play.pngbin0 -> 1059 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/pvrinput.pngbin0 -> 1976 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/quickepgsearch.pngbin0 -> 4781 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/radio.pngbin0 -> 2016 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/remote.pngbin0 -> 3807 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/remotetimers.pngbin0 -> 4372 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/rssreader.pngbin0 -> 2620 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/sc.pngbin0 -> 2208 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/screenshot.pngbin0 -> 2526 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/seduatmo.pngbin0 -> 2024 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/skyselectfeeds.pngbin0 -> 2852 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/sleeptimer.pngbin0 -> 4694 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/softhddevice.pngbin0 -> 2410 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/streamdev-server.pngbin0 -> 2821 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/systeminfo.pngbin0 -> 1709 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/targavfd.pngbin0 -> 1421 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/trayopenng.pngbin0 -> 1077 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/tvguide.pngbin0 -> 2129 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/tvm2vdr.pngbin0 -> 2622 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/tvscraper.pngbin0 -> 2726 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/undelete.pngbin0 -> 2947 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/weatherng.pngbin0 -> 1726 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/xmltv2vdr.pngbin0 -> 2985 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/pluginicons/yaepghg.pngbin0 -> 2129 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/CAM.pngbin0 -> 1619 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/Channels.pngbin0 -> 3561 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/Commands.pngbin0 -> 2428 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/DVB.pngbin0 -> 2758 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/EPG.pngbin0 -> 2874 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/LNB.pngbin0 -> 3739 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/Miscellaneous.pngbin0 -> 1576 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/OSD.pngbin0 -> 1577 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/Plugins.pngbin0 -> 2230 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/Recording.pngbin0 -> 1115 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/Recordings.pngbin0 -> 3640 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/Replay.pngbin0 -> 1059 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/Restart.pngbin0 -> 2577 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/Schedule.pngbin0 -> 2056 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/Setup.pngbin0 -> 3179 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/StopRecording.pngbin0 -> 547 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/StopReplay.pngbin0 -> 1595 bytes
-rw-r--r--skins/nopacity/graphics/menuicons/standardicons/Timers.pngbin0 -> 4113 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/buttonblue.pngbin0 -> 13973 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/buttongreen.pngbin0 -> 14537 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/buttonred.pngbin0 -> 13011 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/buttonyellow.pngbin0 -> 13919 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/channellogoback.pngbin0 -> 35436 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/discpercent.pngbin0 -> 4553 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/displaychannelback.pngbin0 -> 324403 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/displaychanneltop.pngbin0 -> 8987 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/displayreplayback.pngbin0 -> 321112 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/displayreplaytop.pngbin0 -> 4881 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/displayvolume.pngbin0 -> 58704 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/headertop.pngbin0 -> 5295 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/menubutton.pngbin0 -> 9360 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/menubuttonactive.pngbin0 -> 11656 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/menubuttondefault.pngbin0 -> 60910 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/menubuttondefaultactive.pngbin0 -> 64422 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/menubuttontop.pngbin0 -> 3772 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/messageError.pngbin0 -> 114302 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/messageInfo.pngbin0 -> 120782 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/messageStatus.pngbin0 -> 120430 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/messageWarning.pngbin0 -> 116747 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/scrollbar.pngbin0 -> 11893 bytes
-rw-r--r--skins/nopacity/graphics/skinparts/signal.pngbin0 -> 2436 bytes
-rw-r--r--skins/nopacity/xmlfiles/displayaudiotracks.xml46
-rw-r--r--skins/nopacity/xmlfiles/displaychannel.xml218
-rw-r--r--skins/nopacity/xmlfiles/displaymenu.xml188
-rw-r--r--skins/nopacity/xmlfiles/displaymenuchannels.xml127
-rw-r--r--skins/nopacity/xmlfiles/displaymenudefault.xml65
-rw-r--r--skins/nopacity/xmlfiles/displaymenudetailepg.xml256
-rw-r--r--skins/nopacity/xmlfiles/displaymenudetailrecording.xml233
-rw-r--r--skins/nopacity/xmlfiles/displaymenudetailtext.xml25
-rw-r--r--skins/nopacity/xmlfiles/displaymenumain.xml138
-rw-r--r--skins/nopacity/xmlfiles/displaymenurecordings.xml93
-rw-r--r--skins/nopacity/xmlfiles/displaymenuschedules.xml211
-rw-r--r--skins/nopacity/xmlfiles/displaymenusetup.xml45
-rw-r--r--skins/nopacity/xmlfiles/displaymenutimers.xml98
-rw-r--r--skins/nopacity/xmlfiles/displaymessage.xml28
-rw-r--r--skins/nopacity/xmlfiles/displayreplay.xml218
-rw-r--r--skins/nopacity/xmlfiles/displayvolume.xml40
-rw-r--r--skins/nopacity/xmlfiles/globals.xml207
-rw-r--r--skinskeleton/xmlfiles/displayaudiotracks.xml30
-rw-r--r--skinskeleton/xmlfiles/displaychannel.xml126
-rw-r--r--skinskeleton/xmlfiles/displaymenu.xml87
-rw-r--r--skinskeleton/xmlfiles/displaymenuchannels.xml74
-rw-r--r--skinskeleton/xmlfiles/displaymenudefault.xml36
-rw-r--r--skinskeleton/xmlfiles/displaymenudetailepg.xml165
-rw-r--r--skinskeleton/xmlfiles/displaymenudetailrecording.xml154
-rw-r--r--skinskeleton/xmlfiles/displaymenudetailtext.xml9
-rw-r--r--skinskeleton/xmlfiles/displaymenumain.xml79
-rw-r--r--skinskeleton/xmlfiles/displaymenurecordings.xml49
-rw-r--r--skinskeleton/xmlfiles/displaymenuschedules.xml73
-rw-r--r--skinskeleton/xmlfiles/displaymenusetup.xml27
-rw-r--r--skinskeleton/xmlfiles/displaymenutimers.xml58
-rw-r--r--skinskeleton/xmlfiles/displaymessage.xml19
-rw-r--r--skinskeleton/xmlfiles/displayreplay.xml117
-rw-r--r--skinskeleton/xmlfiles/displayvolume.xml18
-rw-r--r--skinskeleton/xmlfiles/globals.xml37
-rw-r--r--themes/skindesigner-default.theme1
-rw-r--r--themes/skindesigner-nopacity.theme1
-rw-r--r--views/displayaudiotracksview.c79
-rw-r--r--views/displayaudiotracksview.h24
-rw-r--r--views/displaychannelview.c452
-rw-r--r--views/displaychannelview.h49
-rw-r--r--views/displaymenudetailview.c929
-rw-r--r--views/displaymenudetailview.h50
-rw-r--r--views/displaymenuitemcurrentview.c561
-rw-r--r--views/displaymenuitemcurrentview.h94
-rw-r--r--views/displaymenuitemview.c731
-rw-r--r--views/displaymenuitemview.h141
-rw-r--r--views/displaymenulistview.c216
-rw-r--r--views/displaymenulistview.h35
-rw-r--r--views/displaymenurootview.c495
-rw-r--r--views/displaymenurootview.h57
-rw-r--r--views/displaymenutabview.c126
-rw-r--r--views/displaymenutabview.h27
-rw-r--r--views/displaymenuview.c539
-rw-r--r--views/displaymenuview.h60
-rw-r--r--views/displaymessageview.c49
-rw-r--r--views/displaymessageview.h19
-rw-r--r--views/displayreplayview.c376
-rw-r--r--views/displayreplayview.h32
-rw-r--r--views/displayvolumeview.c55
-rw-r--r--views/displayvolumeview.h21
-rw-r--r--views/view.c809
-rw-r--r--views/view.h72
503 files changed, 24368 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..f90922e
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..23775a8
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,7 @@
+VDR Plugin 'skindesigner' Revision History
+---------------------------------------
+
+2014-09-27: Version 0.0.1
+
+- Initial revision.
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1b32acc
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,176 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+# $Id$ Makefile 1.0 2014/07/24 louis Exp $
+
+# External image lib to use: imagemagick, graphicsmagick
+IMAGELIB = imagemagick
+
+# The official name of this plugin.
+PLUGIN = skindesigner
+
+### The version number of this plugin (taken from the main source file):
+VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
+
+### The directory environment:
+
+# Use package data if installed...otherwise assume we're under the VDR source directory:
+PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc))
+LIBDIR = $(call PKGCFG,libdir)
+LOCDIR = $(call PKGCFG,locdir)
+PLGCFG = $(call PKGCFG,plgcfg)
+VDRCONFDIR = $(call PKGCFG,configdir)
+PLGRESDIR = $(call PKGCFG,resdir)/plugins/$(PLUGIN)
+TMPDIR ?= /tmp
+
+### The compiler options:
+export CFLAGS = $(call PKGCFG,cflags)
+export CXXFLAGS = $(call PKGCFG,cxxflags)
+
+### Allow user defined options to overwrite defaults:
+
+-include $(PLGCFG)
+
+### The version number of VDR's plugin API:
+APIVERSION = $(call PKGCFG,apiversion)
+
+### The name of the distribution archive:
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### The name of the shared object file:
+SOFILE = libvdr-$(PLUGIN).so
+
+### Includes and Defines and Dependencies:
+DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+DEFINES += $(shell xml2-config --cflags)
+
+INCLUDES += $(shell pkg-config --cflags freetype2 fontconfig)
+
+ifeq ($(IMAGELIB), imagemagick)
+ INCLUDES += $(shell pkg-config --cflags Magick++)
+ LIBS += $(shell pkg-config --libs Magick++)
+else ifeq ($(IMAGELIB), graphicsmagick)
+ INCLUDES += $(shell pkg-config --cflags GraphicsMagick++)
+ LIBS += $(shell pkg-config --libs GraphicsMagick++)
+endif
+
+LIBS += $(shell xml2-config --libs)
+
+### The object files:
+OBJS = $(PLUGIN).o \
+ config.o \
+ setup.o \
+ designer.o \
+ displaychannel.o \
+ displaymenu.o \
+ displaymessage.o \
+ displayreplay.o \
+ displaytracks.o \
+ displayvolume.o \
+ libcore/pixmapcontainer.o \
+ libcore/fontmanager.o \
+ libcore/imagecache.o \
+ libcore/imagemagickwrapper.o \
+ libcore/imagescaler.o \
+ libcore/helpers.o \
+ libcore/imageloader.o \
+ libcore/timers.o \
+ libtemplate/globals.o \
+ libtemplate/parameter.o \
+ libtemplate/template.o \
+ libtemplate/templateview.o \
+ libtemplate/templateviewelement.o \
+ libtemplate/templateviewlist.o \
+ libtemplate/templatepixmap.o \
+ libtemplate/templateviewtab.o \
+ libtemplate/templatefunction.o \
+ libtemplate/templateloopfunction.o \
+ libtemplate/xmlparser.o \
+ views/view.o \
+ views/displaychannelview.o \
+ views/displaymenurootview.o \
+ views/displaymenuview.o \
+ views/displaymenulistview.o \
+ views/displaymenuitemview.o \
+ views/displaymenuitemcurrentview.o \
+ views/displaymenudetailview.o \
+ views/displaymenutabview.o \
+ views/displaymessageview.o \
+ views/displayreplayview.o \
+ views/displayvolumeview.o \
+ views/displayaudiotracksview.o
+
+### The main target:
+
+all: $(SOFILE) i18n
+
+### Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+
+### Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Internationalization (I18N):
+
+PODIR = po
+I18Npo = $(wildcard $(PODIR)/*.po)
+I18Nmo = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file))))
+I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
+I18Npot = $(PODIR)/$(PLUGIN).pot
+
+%.mo: %.po
+ msgfmt -c -o $@ $<
+
+$(I18Npot): $(wildcard *.c)
+ xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
+
+%.po: $(I18Npot)
+ msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
+ @touch $@
+
+$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
+ install -D -m644 $< $@
+
+.PHONY: i18n
+i18n: $(I18Nmo) $(I18Npot)
+
+install-i18n: $(I18Nmsgs)
+
+### Targets:
+
+$(SOFILE): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@
+
+install-lib: $(SOFILE)
+ install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
+
+install-themes:
+ mkdir -p $(DESTDIR)$(VDRCONFDIR)/themes
+ cp themes/* $(DESTDIR)$(VDRCONFDIR)/themes
+
+install-skins:
+ mkdir -p $(DESTDIR)$(PLGRESDIR)/skins
+ cp -r skins/* $(DESTDIR)$(PLGRESDIR)/skins
+
+install: install-lib install-i18n install-themes install-skins
+
+dist: $(I18Npo) clean
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @mkdir $(TMPDIR)/$(ARCHIVE)
+ @cp -a * $(TMPDIR)/$(ARCHIVE)
+ @tar czf $(PACKAGE).tgz --exclude .git* --exclude *.o --exclude *.rej --exclude *.orig -C $(TMPDIR) $(ARCHIVE)
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @echo Distribution package created as $(PACKAGE).tgz
+
+clean:
+ @-rm -f $(PODIR)/*.mo $(PODIR)/*.pot
+ @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~
diff --git a/README b/README
new file mode 100644
index 0000000..3f1a3f2
--- /dev/null
+++ b/README
@@ -0,0 +1,102 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by: Louis Braun <louis DOT braun AT gmx DOT de>
+
+Project's homepage: http://projects.vdr-developer.org/projects/plg-skindesigner
+
+Latest version: http://projects.vdr-developer.org/projects/plg-skindesigner/files
+GIT repository: git clone git://projects.vdr-developer.org/plg-skindesigner.git
+
+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 of the License, or
+(at your option) any later version.
+See the file COPYING for more information.
+
+Description
+-----------
+
+Skindesigner is a VDR skin engine that displays XML based Skins.
+
+Currently two XML Skins (MetrixHD and nOpacity freestyle) are included in
+<pluginsourcedir>/skins/
+
+Requirements
+------------
+
+- VDR version >= 2.0.0
+
+- Installed ImageMagick or GraphicsMagick for displaying png/jpg Icons, Channel Logos
+ and EPG Images (configurable during make via IMAGELIB = imagemagick|graphicsmagick
+ parameter)
+
+- libxml2
+
+- for scaling the video picture to fit into the VDR menu window please use
+ softhddevice plugin revision 87c1c7be (2013-01-01) or newer.
+
+- epgsearch Git since commit ba7c6277 (2013-01-03) to correctly replace the schedules
+ menu with epgsearch
+
+Installation
+------------
+
+After "normal" Plugin installation you have to care about the paths for the
+XML skins and epg images. The following paths can be set at startup:
+
+-s <SKINPATH>, --skinpath=<SKINPATH>
+ Path to the XML skins (Default: <ResourceDirectory>/plugins/skindesigner/skins/)
+
+-e path, --epgimages=path
+ Path to the epgimages (Default: <CacheDirectory>/epgimages/)
+
+ResourceDirectory and CacheDirectory are taken from your VDR configuration (make.config
+or vdr.pc).
+
+During a "make install" the included skins are automatically copied from
+<SkinSourceDirectory>/skins/ to the configured path.
+
+For S2-6400 Users: Disable High Level OSD, otherwise the plugin will not be
+loaded because lack of true color support
+
+For Xine-Plugin Users: Set "Blend scaled Auto" as OSD display mode to achieve
+an suitable true color OSD.
+
+For Xineliboutput Users: Start vdr-sxfe with the --hud option enabled
+
+Since the default skin MetrixHD uses VDROpenSans as font which is not installed per
+default, you may want to install this font (included in <SkinSourceDirectory>/fonts/)
+first. Otherwise the inside VDRs OSD menu configured vdrOsd Font is used as default.
+
+Channel Logos
+-------------
+
+Since each XML skin is responsible for it's used channel logos, skindesigner searches
+for channel logos only in the skin dependend directory
+
+<ResourceDirectory>/plugins/skindesigner/skins/<skinname>/logos
+
+Each copy your used logos directly to this directory or set a symbolic link to a common
+channellogo directory.
+
+I recommend to use channel logos from https://github.com/3PO/Senderlogos
+To download them just change in the directory you want to place the logos
+and do a:
+git clone https://github.com/3PO/Senderlogos.git logos
+An update of the logos can then be done with a "git pull" just inside this
+directory.
+
+In this logo pack all files are named only with lower case letters.
+Skindesigner uses the channel name CONVERTED TO LOWER CASE LETTERS to search for an
+appropriate channel logo. With this, approximately 90% of the channel logos should work
+immediately after placing the channel logos in the correct place. So if you have to change
+the name of a channel logo (may be by inserting a space or a hyphen) so that it fits to
+the channel name, only use lower case letters, and not the name of the channel with upper
+and lower letters as displayed inside VDR.
+If no logo is found for the channel name, additionally a search for a logo named as the
+ChannelID is performed. Analog to the channel name the ChannelID is also converted to lower
+case letters. This allows channel logos for channels with changing names (for instance
+Sky Feed Channels).
+Additional hint: some channels have slashes in their name (in germany nick/comedy for instance).
+In this example, as a dirty hack just create a folder in your channel logo directory named
+"nick" and place an image named "comedy.png" inside this folder.
diff --git a/config.c b/config.c
new file mode 100644
index 0000000..3b88b8e
--- /dev/null
+++ b/config.c
@@ -0,0 +1,76 @@
+#include "config.h"
+#include "libcore/helpers.h"
+#include "libcore/imageloader.h"
+
+cDesignerConfig::cDesignerConfig() {
+ epgImagePathSet = false;
+ skinPathSet = false;
+ //Common
+ logoExtension = "png";
+ numLogosPerSizeInitial = 30;
+ limitLogoCache = 1;
+ numLogosMax = 200;
+ debugImageLoading = 0;
+ //default logo width and height
+ logoWidth = 268;
+ logoHeight = 200;
+ replaceDecPoint = false;
+}
+
+cDesignerConfig::~cDesignerConfig() {
+}
+
+void cDesignerConfig::SetPathes(void) {
+ if (!skinPathSet)
+ skinPath = cString::sprintf("%s/skins/", cPlugin::ResourceDirectory(PLUGIN_NAME_I18N));
+ if (!epgImagePathSet)
+ epgImagePath = cString::sprintf("%s/epgimages/", cPlugin::CacheDirectory(PLUGIN_NAME_I18N));
+
+ dsyslog("skindesigner: using Skin Directory %s", *skinPath);
+ dsyslog("skindesigner: using EPG Images Directory %s", *epgImagePath);
+
+}
+
+void cDesignerConfig::SetSkinPath(cString path) {
+ skinPath = CheckSlashAtEnd(*path);
+ skinPathSet = true;
+}
+
+void cDesignerConfig::SetEpgImagePath(cString path) {
+ epgImagePath = CheckSlashAtEnd(*path);
+ epgImagePathSet = true;
+}
+
+void cDesignerConfig::SetChannelLogoSize(void) {
+ cImageLoader imgLoader;
+ imgLoader.DeterminateChannelLogoSize(logoWidth, logoHeight);
+ dsyslog("skindesigner: using %dx%d px as original channel logo size", logoWidth, logoHeight);
+}
+
+void cDesignerConfig::CheckDecimalPoint(void) {
+ struct lconv *pLocInfo;
+ pLocInfo = localeconv();
+ string decimalPoint = pLocInfo->decimal_point;
+ if (decimalPoint.compare(".")) {
+ dsyslog("skindesigner: using decimal point %s", decimalPoint.c_str());
+ replaceDecPoint = true;
+ decPoint = decimalPoint[0];
+ }
+}
+
+cString cDesignerConfig::CheckSlashAtEnd(std::string path) {
+ try {
+ if (!(path.at(path.size()-1) == '/'))
+ return cString::sprintf("%s/", path.c_str());
+ } catch (...) {return path.c_str();}
+ return path.c_str();
+}
+
+bool cDesignerConfig::SetupParse(const char *Name, const char *Value) {
+ if (!strcasecmp(Name, "DebugImageLoading")) debugImageLoading = atoi(Value);
+ else if (!strcasecmp(Name, "LimitChannelLogoCache")) limitLogoCache = atoi(Value);
+ else if (!strcasecmp(Name, "NumberLogosInitially")) numLogosPerSizeInitial = atoi(Value);
+ else if (!strcasecmp(Name, "NumberLogosMax")) numLogosMax = atoi(Value);
+ else return false;
+ return true;
+}
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..73fb54f
--- /dev/null
+++ b/config.h
@@ -0,0 +1,53 @@
+#ifndef __DESIGNER_CONFIG_H
+#define __DESIGNER_CONFIG_H
+
+#include <string>
+#include <vector>
+#include <map>
+#include <vdr/tools.h>
+#include <vdr/skins.h>
+#include <vdr/plugin.h>
+#include "libcore/fontmanager.h"
+#include "libcore/imagecache.h"
+
+class cDesignerConfig {
+private:
+ cString CheckSlashAtEnd(std::string path);
+ bool epgImagePathSet;
+ bool skinPathSet;
+public:
+ cDesignerConfig();
+ ~cDesignerConfig();
+ bool SetupParse(const char *Name, const char *Value);
+ void SetSkinPath(cString path);
+ void SetEpgImagePath(cString path);
+ void SetPathes(void);
+ void SetChannelLogoSize(void);
+ void CheckDecimalPoint(void);
+ cString logoExtension;
+ cString skinPath;
+ cString epgImagePath;
+ int numLogosPerSizeInitial;
+ int limitLogoCache;
+ int numLogosMax;
+ int debugImageLoading;
+ int logoWidth;
+ int logoHeight;
+ bool replaceDecPoint;
+ char decPoint;
+};
+#ifdef DEFINE_CONFIG
+ bool firstDisplay = true;
+ cDesignerConfig config;
+ cFontManager *fontManager;
+ cImageCache *imgCache;
+ cTheme Theme;
+#else
+ extern bool firstDisplay;
+ extern cDesignerConfig config;
+ extern cFontManager *fontManager;
+ extern cImageCache *imgCache;
+ extern cTheme Theme;
+#endif
+
+#endif //__DESIGNER_CONFIG_H
diff --git a/designer.c b/designer.c
new file mode 100644
index 0000000..61d0cfd
--- /dev/null
+++ b/designer.c
@@ -0,0 +1,309 @@
+#include "designer.h"
+#include "libcore/helpers.h"
+
+cSkinDesigner::cSkinDesigner(void) : cSkin("skindesigner", &::Theme) {
+ backupSkin = NULL;
+ useBackupSkin = false;
+
+ SetOSDSize();
+ osdTheme = Setup.OSDTheme;
+ config.SetPathes();
+ config.SetChannelLogoSize();
+ config.CheckDecimalPoint();
+ fontManager = new cFontManager();
+ imgCache = new cImageCache();
+
+ globals = NULL;
+ channelTemplate = NULL;
+ menuTemplate = NULL;
+ messageTemplate = NULL;
+ replayTemplate = NULL;
+ volumeTemplate = NULL;
+ audiotracksTemplate = NULL;
+
+ cStopWatch watch;
+ bool ok = LoadTemplates();
+ if (!ok) {
+ esyslog("skindesigner: error during loading of templates - using LCARS as backup");
+ backupSkin = new cSkinLCARS();
+ useBackupSkin = true;
+ } else {
+ CacheTemplates();
+ watch.Stop("templates loaded and cache created");
+ }
+}
+
+cSkinDesigner::~cSkinDesigner(void) {
+ if (globals)
+ delete globals;
+ DeleteTemplates();
+ if (backupSkin)
+ delete backupSkin;
+}
+
+const char *cSkinDesigner::Description(void) {
+ return "SkinDesigner";
+}
+
+cSkinDisplayChannel *cSkinDesigner::DisplayChannel(bool WithInfo) {
+ cSkinDisplayChannel *displayChannel = NULL;
+ if (!useBackupSkin) {
+ ReloadCaches();
+ displayChannel = new cSDDisplayChannel(channelTemplate, WithInfo);
+ } else {
+ displayChannel = backupSkin->DisplayChannel(WithInfo);
+ }
+ return displayChannel;
+}
+
+cSkinDisplayMenu *cSkinDesigner::DisplayMenu(void) {
+ cSkinDisplayMenu *displayMenu = NULL;
+ if (!useBackupSkin) {
+ ReloadCaches();
+ displayMenu = new cSDDisplayMenu(menuTemplate);
+ } else {
+ displayMenu = backupSkin->DisplayMenu();
+ }
+ return displayMenu;
+}
+
+cSkinDisplayReplay *cSkinDesigner::DisplayReplay(bool ModeOnly) {
+ cSkinDisplayReplay *displayReplay = NULL;
+ if (!useBackupSkin) {
+ ReloadCaches();
+ displayReplay = new cSDDisplayReplay(replayTemplate, ModeOnly);
+ } else {
+ displayReplay = backupSkin->DisplayReplay(ModeOnly);
+ }
+ return displayReplay;
+}
+
+cSkinDisplayVolume *cSkinDesigner::DisplayVolume(void) {
+ cSkinDisplayVolume *displayVolume = NULL;
+ if (!useBackupSkin) {
+ ReloadCaches();
+ displayVolume = new cSDDisplayVolume(volumeTemplate);
+ } else {
+ displayVolume = backupSkin->DisplayVolume();
+ }
+ return displayVolume;
+}
+
+cSkinDisplayTracks *cSkinDesigner::DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks) {
+ cSkinDisplayTracks *displayTracks = NULL;
+ if (!useBackupSkin) {
+ ReloadCaches();
+ displayTracks = new cSDDisplayTracks(audiotracksTemplate, Title, NumTracks, Tracks);
+ } else {
+ displayTracks = backupSkin->DisplayTracks(Title, NumTracks, Tracks);
+ }
+ return displayTracks;
+}
+
+cSkinDisplayMessage *cSkinDesigner::DisplayMessage(void) {
+ cSkinDisplayMessage *displayMessage = NULL;
+ if (!useBackupSkin) {
+ ReloadCaches();
+ displayMessage = new cSDDisplayMessage(messageTemplate);
+ } else {
+ displayMessage = backupSkin->DisplayMessage();
+ }
+ return displayMessage;
+}
+
+void cSkinDesigner::Reload(void) {
+ dsyslog("skindesigner: forcing full reload of templates");
+ if (cOsd::IsOpen()) {
+ esyslog("skindesigner: OSD is open, close first!");
+ return;
+ }
+ DeleteTemplates();
+ cStopWatch watch;
+ bool ok = LoadTemplates();
+ if (!ok) {
+ esyslog("skindesigner: error during loading of templates - using LCARS as backup");
+ if (!backupSkin)
+ backupSkin = new cSkinLCARS();
+ useBackupSkin = true;
+ } else {
+ CacheTemplates();
+ useBackupSkin = false;
+ watch.Stop("templates reloaded and cache created");
+ }
+}
+
+void cSkinDesigner::ListAvailableFonts(void) {
+ fontManager->ListAvailableFonts();
+}
+
+/*********************************************************************************
+* PRIVATE FUNCTIONS
+*********************************************************************************/
+void cSkinDesigner::DeleteTemplates(void) {
+ if (channelTemplate) {
+ delete channelTemplate;
+ channelTemplate = NULL;
+ }
+ if (menuTemplate) {
+ delete menuTemplate;
+ menuTemplate = NULL;
+ }
+ if (messageTemplate) {
+ delete messageTemplate;
+ messageTemplate = NULL;
+ }
+ if (replayTemplate) {
+ delete replayTemplate;
+ replayTemplate = NULL;
+ }
+ if (volumeTemplate) {
+ delete volumeTemplate;
+ volumeTemplate = NULL;
+ }
+ if (audiotracksTemplate) {
+ delete audiotracksTemplate;
+ audiotracksTemplate = NULL;
+ }
+}
+
+bool cSkinDesigner::LoadTemplates(void) {
+
+ globals = new cGlobals();
+ bool ok = globals->ReadFromXML();
+ if (!ok) {
+ esyslog("skindesigner: error parsing globals, aborting");
+ return false;
+ }
+ //globals->Debug();
+
+ DeleteTemplates();
+
+ channelTemplate = new cTemplate(vtDisplayChannel);
+ channelTemplate->SetGlobals(globals);
+ ok = channelTemplate->ReadFromXML();
+ if (!ok) {
+ esyslog("skindesigner: error reading displaychannel template, aborting");
+ DeleteTemplates();
+ return false;
+ }
+ channelTemplate->Translate();
+
+ menuTemplate = new cTemplate(vtDisplayMenu);
+ menuTemplate->SetGlobals(globals);
+ ok = menuTemplate->ReadFromXML();
+ if (!ok) {
+ esyslog("skindesigner: error reading displaymenu template, aborting");
+ DeleteTemplates();
+ return false;
+ }
+ menuTemplate->Translate();
+
+ messageTemplate = new cTemplate(vtDisplayMessage);
+ messageTemplate->SetGlobals(globals);
+ ok = messageTemplate->ReadFromXML();
+ if (!ok) {
+ esyslog("skindesigner: error reading displaymessage template, aborting");
+ DeleteTemplates();
+ return false;
+ }
+ messageTemplate->Translate();
+
+ replayTemplate = new cTemplate(vtDisplayReplay);
+ replayTemplate->SetGlobals(globals);
+ ok = replayTemplate->ReadFromXML();
+ if (!ok) {
+ esyslog("skindesigner: error reading displayreplay template, aborting");
+ DeleteTemplates();
+ return false;
+ }
+ replayTemplate->Translate();
+
+ volumeTemplate = new cTemplate(vtDisplayVolume);
+ volumeTemplate->SetGlobals(globals);
+ ok = volumeTemplate->ReadFromXML();
+ if (!ok) {
+ esyslog("skindesigner: error reading displayvolume template, aborting");
+ DeleteTemplates();
+ return false;
+ }
+ volumeTemplate->Translate();
+
+ audiotracksTemplate = new cTemplate(vtDisplayAudioTracks);
+ audiotracksTemplate->SetGlobals(globals);
+ ok = audiotracksTemplate->ReadFromXML();
+ if (!ok) {
+ esyslog("skindesigner: error reading displayaudiotracks template, aborting");
+ DeleteTemplates();
+ return false;
+ }
+ audiotracksTemplate->Translate();
+
+ dsyslog("skindesigner: templates successfully validated and parsed");
+ return true;
+}
+
+void cSkinDesigner::CacheTemplates(void) {
+ channelTemplate->PreCache();
+ menuTemplate->PreCache();
+ messageTemplate->PreCache();
+ replayTemplate->PreCache();
+ volumeTemplate->PreCache();
+ audiotracksTemplate->PreCache();
+ dsyslog("skindesigner: templates cached");
+ fontManager->CacheFonts(channelTemplate);
+ fontManager->CacheFonts(menuTemplate);
+ fontManager->CacheFonts(messageTemplate);
+ fontManager->CacheFonts(replayTemplate);
+ fontManager->CacheFonts(volumeTemplate);
+ fontManager->CacheFonts(audiotracksTemplate);
+ dsyslog("skindesigner: fonts cached");
+ dsyslog("skindesigner: caching images...");
+ imgCache->Clear();
+ channelTemplate->CacheImages();
+ menuTemplate->CacheImages();
+ messageTemplate->CacheImages();
+ replayTemplate->CacheImages();
+ volumeTemplate->CacheImages();
+ audiotracksTemplate->CacheImages();
+ imgCache->Debug(false);
+}
+
+void cSkinDesigner::ReloadCaches(void) {
+ if (OsdSizeChanged() || ThemeChanged()) {
+ cStopWatch watch;
+ bool ok = LoadTemplates();
+ if (ok) {
+ CacheTemplates();
+ }
+ watch.Stop("templates reloaded and cache recreated");
+ }
+}
+
+void cSkinDesigner::SetOSDSize(void) {
+ osdSize.SetWidth(cOsd::OsdWidth());
+ osdSize.SetHeight(cOsd::OsdHeight());
+ osdSize.SetX(cOsd::OsdLeft());
+ osdSize.SetY(cOsd::OsdTop());
+}
+
+bool cSkinDesigner::OsdSizeChanged(void) {
+ if ((osdSize.Width() != cOsd::OsdWidth()) ||
+ (osdSize.Height() != cOsd::OsdHeight()) ||
+ (osdSize.X() != cOsd::OsdLeft()) ||
+ (osdSize.Y() != cOsd::OsdTop())) {
+ dsyslog("skindesigner: osd size changed");
+ dsyslog("skindesigner: old osd size: top %d left %d size %d * %d", osdSize.X(), osdSize.Y(), osdSize.Width(), osdSize.Height());
+ SetOSDSize();
+ dsyslog("skindesigner: new osd size: top %d left %d size %d * %d", osdSize.X(), osdSize.Y(), osdSize.Width(), osdSize.Height());
+ return true;
+ }
+ return false;
+}
+
+bool cSkinDesigner::ThemeChanged(void) {
+ if (osdTheme.compare(Setup.OSDTheme) != 0) {
+ osdTheme = Setup.OSDTheme;
+ return true;
+ }
+ return false;
+} \ No newline at end of file
diff --git a/designer.h b/designer.h
new file mode 100644
index 0000000..4ba4f63
--- /dev/null
+++ b/designer.h
@@ -0,0 +1,49 @@
+#ifndef __SKINDESIGNER_H
+#define __SKINDESIGNER_H
+
+#include "config.h"
+#include "libtemplate/template.h"
+#include "libtemplate/xmlparser.h"
+#include "displaychannel.h"
+#include "displaymenu.h"
+#include "displayreplay.h"
+#include "displayvolume.h"
+#include "displaytracks.h"
+#include "displaymessage.h"
+#include <vdr/skinlcars.h>
+
+class cSkinDesigner : public cSkin {
+private:
+ cSkinLCARS *backupSkin;
+ bool useBackupSkin;
+ cRect osdSize;
+ std::string osdTheme;
+ cGlobals *globals;
+ cTemplate *channelTemplate;
+ cTemplate *menuTemplate;
+ cTemplate *messageTemplate;
+ cTemplate *replayTemplate;
+ cTemplate *volumeTemplate;
+ cTemplate *audiotracksTemplate;
+ void DeleteTemplates(void);
+ void ReloadCaches(void);
+ bool LoadTemplates(void);
+ void CacheTemplates(void);
+ void SetOSDSize(void);
+ bool OsdSizeChanged(void);
+ bool ThemeChanged(void);
+public:
+ cSkinDesigner(void);
+ virtual ~cSkinDesigner(void);
+ virtual const char *Description(void);
+ virtual cSkinDisplayChannel *DisplayChannel(bool WithInfo);
+ virtual cSkinDisplayMenu *DisplayMenu(void);
+ virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly);
+ virtual cSkinDisplayVolume *DisplayVolume(void);
+ virtual cSkinDisplayTracks *DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
+ virtual cSkinDisplayMessage *DisplayMessage(void);
+ void Reload(void);
+ void ListAvailableFonts(void);
+};
+
+#endif //__SKINDESIGNER_H
diff --git a/displaychannel.c b/displaychannel.c
new file mode 100644
index 0000000..4e99002
--- /dev/null
+++ b/displaychannel.c
@@ -0,0 +1,193 @@
+#include "displaychannel.h"
+#include "libcore/timers.h"
+
+cSDDisplayChannel::cSDDisplayChannel(cTemplate *channelTemplate, bool WithInfo) {
+ if (firstDisplay) {
+ firstDisplay = false;
+ doOutput = false;
+ return;
+ } else if (!channelTemplate) {
+ esyslog("skindesigner: displayChannel no valid template - aborting");
+ doOutput = false;
+ return;
+ } else {
+ doOutput = true;
+ }
+ groupSep = false;
+ present = NULL;
+ currentLast = 0;
+ channelChange = false;
+ initial = true;
+
+ channelView = new cDisplayChannelView(channelTemplate->GetRootView());
+ if (!channelView->createOsd()) {
+ doOutput = false;
+ return;
+ }
+ channelView->DrawBackground();
+ channelView->DrawSignalBackground();
+}
+
+cSDDisplayChannel::~cSDDisplayChannel() {
+ if (!doOutput)
+ return;
+ delete channelView;
+}
+
+void cSDDisplayChannel::SetChannel(const cChannel *Channel, int Number) {
+ if (!doOutput)
+ return;
+
+ channelChange = true;
+ groupSep = false;
+
+ cString ChannelNumber("");
+ cString ChannelName("");
+ cString ChannelID("");
+
+ if (Channel) {
+ ChannelName = Channel->Name();
+ ChannelID = Channel->GetChannelID().ToString();
+ if (!Channel->GroupSep()) {
+ ChannelNumber = cString::sprintf("%d%s", Channel->Number(), Number ? "-" : "");
+ } else {
+ groupSep = true;
+ }
+ } else if (Number) {
+ ChannelNumber = cString::sprintf("%d-", Number);
+ } else {
+ ChannelName = ChannelString(NULL, 0);
+ }
+ channelView->ClearChannel();
+ channelView->ClearEPGInfo();
+ channelView->ClearStatusIcons();
+ channelView->ClearChannelGroups();
+ channelView->ClearScraperContent();
+ if (!groupSep) {
+ channelView->DrawChannel(ChannelNumber, ChannelName, ChannelID, (Number > 0)?true:false);
+ channelView->DrawProgressBarBack();
+ channelView->DrawSignalBackground();
+ if (Channel)
+ channelView->DrawStatusIcons(Channel);
+ } else {
+ channelView->ClearSignal();
+ channelView->ClearSignalBackground();
+ channelView->ClearProgressBar();
+ channelView->ClearProgressBarBack();
+ if (Channel)
+ channelView->DrawChannelGroups(Channel, ChannelName);
+ }
+
+}
+
+void cSDDisplayChannel::SetEvents(const cEvent *Present, const cEvent *Following) {
+ if (!doOutput)
+ return;
+
+ present = Present;
+ channelView->ClearProgressBar();
+ if (!groupSep) {
+ channelView->ClearEPGInfo();
+ }
+
+ cGlobalSortedTimers SortedTimers;// local and remote timers
+
+ bool recPresent = false;
+ if (Present) {
+ if (!groupSep) {
+ SetProgressBar(Present);
+ }
+ eTimerMatch TimerMatch = tmNone;
+ const cTimer *Timer = Timers.GetMatch(Present, &TimerMatch);
+ if (Timer && Timer->Recording()) {
+ recPresent = true;
+ }
+ for (int i = 0; i < SortedTimers.Size() && !recPresent; i++)
+ if (const cTimer *Timer = SortedTimers[i])
+ if (Timer->Channel()->GetChannelID() == Present->ChannelID())
+ if (const cEvent *timerEvent = Timer->Event())
+ if (Present->EventID() == timerEvent->EventID())
+ recPresent = Timer->Recording();
+
+ }
+ bool recFollowing = false;
+ if (Following) {
+ recFollowing = Following->HasTimer();
+ for (int i = 0; i < SortedTimers.Size() && !recFollowing; i++)
+ if (const cTimer *Timer = SortedTimers[i])
+ if (Timer->Channel()->GetChannelID() == Following->ChannelID())
+ if (const cEvent *timerEvent = Timer->Event())
+ if (Following->EventID() == timerEvent->EventID())
+ recFollowing = true;
+ }
+
+ if (Present || Following) {
+ channelView->DrawEPGInfo(Present, Following, recPresent, recFollowing);
+ channelView->DrawScraperContent(Present);
+ }
+}
+
+void cSDDisplayChannel::SetProgressBar(const cEvent *present) {
+ int Current = 0;
+ int Total = 0;
+ time_t t = time(NULL);
+ if (t > present->StartTime())
+ Current = t - present->StartTime();
+ Total = present->Duration();
+ if ((Current > currentLast + 3) || initial || channelChange) {
+ currentLast = Current;
+ cString start = present->GetTimeString();
+ cString stop = present->GetEndTimeString();
+ channelView->DrawProgressBar(start, stop, Current, Total);
+ }
+}
+
+
+void cSDDisplayChannel::SetMessage(eMessageType Type, const char *Text) {
+ if (!doOutput)
+ return;
+ channelView->ClearChannel();
+ channelView->ClearEPGInfo();
+ channelView->ClearStatusIcons();
+ channelView->ClearScreenResolution();
+ channelView->ClearProgressBar();
+ channelView->ClearProgressBarBack();
+ channelView->ClearSignal();
+ channelView->ClearSignalBackground();
+ channelView->ClearScraperContent();
+ channelView->DisplayMessage(Type, Text);
+ groupSep = true;
+}
+
+void cSDDisplayChannel::Flush(void) {
+ if (!doOutput)
+ return;
+
+ if (initial || channelChange) {
+ channelView->DrawDate();
+ }
+
+ if (present) {
+ SetProgressBar(present);
+ } else {
+ channelView->ClearProgressBar();
+ }
+
+ if (!groupSep) {
+ channelView->DrawScreenResolution();
+ channelView->DrawSignal();
+ } else {
+ channelView->ClearStatusIcons();
+ channelView->ClearScreenResolution();
+ channelView->ClearSignal();
+ channelView->ClearSignalBackground();
+ }
+
+ if (initial) {
+ channelView->DoStart();
+ }
+
+ initial = false;
+ channelChange = false;
+ channelView->Flush();
+} \ No newline at end of file
diff --git a/displaychannel.h b/displaychannel.h
new file mode 100644
index 0000000..44d69e5
--- /dev/null
+++ b/displaychannel.h
@@ -0,0 +1,32 @@
+#ifndef __DISPLAYCHANNEL_H
+#define __DISPLAYCHANNEL_H
+
+#include <vdr/thread.h>
+#include "config.h"
+#include "libtemplate/template.h"
+#include "views/displaychannelview.h"
+
+class cSDDisplayChannel : public cSkinDisplayChannel {
+private:
+ cDisplayChannelView *channelView;
+ bool doOutput;
+ bool initial;
+ bool groupSep;
+ bool channelChange;
+ time_t lastSignalDisplay;
+ int lastSignalStrength;
+ int lastSignalQuality;
+ int lastScreenWidth;
+ int currentLast;
+ bool showSignal;
+ const cEvent *present;
+ void SetProgressBar(const cEvent *present);
+public:
+ cSDDisplayChannel(cTemplate *channelTemplate, bool WithInfo);
+ virtual ~cSDDisplayChannel();
+ virtual void SetChannel(const cChannel *Channel, int Number);
+ virtual void SetEvents(const cEvent *Present, const cEvent *Following);
+ virtual void SetMessage(eMessageType Type, const char *Text);
+ virtual void Flush(void);
+};
+#endif //__DISPLAYCHANNEL_H \ No newline at end of file
diff --git a/displaymenu.c b/displaymenu.c
new file mode 100644
index 0000000..73e489d
--- /dev/null
+++ b/displaymenu.c
@@ -0,0 +1,233 @@
+#include "displaymenu.h"
+#include "libcore/helpers.h"
+
+cSDDisplayMenu::cSDDisplayMenu(cTemplate *menuTemplate) {
+ doOutput = true;
+ state = vsInit;
+ if (!menuTemplate) {
+ doOutput = false;
+ esyslog("skindesigner: displayMenu no valid template - aborting");
+ return;
+ }
+ rootView = new cDisplayMenuRootView(menuTemplate->GetRootView());
+ if (!rootView->createOsd()) {
+ doOutput = false;
+ return;
+ }
+}
+
+cSDDisplayMenu::~cSDDisplayMenu() {
+ if (!doOutput)
+ return;
+ delete rootView;
+}
+
+void cSDDisplayMenu::Scroll(bool Up, bool Page) {
+ if (!doOutput)
+ return;
+ rootView->KeyInput(Up, Page);
+}
+
+int cSDDisplayMenu::MaxItems(void) {
+ if (!doOutput)
+ return 0;
+ int maxItems = rootView->GetMaxItems();
+ return maxItems;
+}
+
+void cSDDisplayMenu::Clear(void) {
+ if (!doOutput)
+ return;
+ rootView->Clear();
+}
+
+void cSDDisplayMenu::SetMenuCategory(eMenuCategory MenuCat) {
+ if (!doOutput)
+ return;
+ rootView->SetMenu(MenuCat, (state == vsInit) ? true : false);
+ cSkinDisplayMenu::SetMenuCategory(MenuCat);
+ if (state != vsInit)
+ state = vsMenuInit;
+}
+
+void cSDDisplayMenu::SetTitle(const char *Title) {
+ if (!doOutput)
+ return;
+ rootView->SetTitle(Title);
+}
+
+void cSDDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue) {
+ if (!doOutput)
+ return;
+ rootView->SetButtonTexts(Red, Green, Yellow, Blue);
+ if (state != vsInit && MenuCategory() != mcMain)
+ state = vsMenuInit;
+}
+
+void cSDDisplayMenu::SetMessage(eMessageType Type, const char *Text) {
+ if (!doOutput)
+ return;
+ rootView->SetMessage(Type, Text);
+ rootView->DoFlush();
+}
+
+bool cSDDisplayMenu::SetItemEvent(const cEvent *Event, int Index, bool Current, bool Selectable, const cChannel *Channel, bool WithDate, eTimerMatch TimerMatch) {
+ if (!doOutput)
+ return true;
+ if (!rootView->SubViewAvailable())
+ return false;
+ if (Current) {
+ if (Channel) {
+ rootView->SetChannel(Channel);
+ } else if (Event) {
+ rootView->SetChannel(Channels.GetByChannelID(Event->ChannelID()));
+ }
+ }
+ cDisplayMenuListView *list = rootView->GetListView();
+ if (!list)
+ return false;
+ list->AddSchedulesMenuItem(Index, Event, Channel, TimerMatch, MenuCategory(), Current, Selectable);
+ if (state == vsIdle)
+ state = vsMenuUpdate;
+ return true;
+}
+
+bool cSDDisplayMenu::SetItemTimer(const cTimer *Timer, int Index, bool Current, bool Selectable) {
+ if (!doOutput)
+ return true;
+ if (!rootView->SubViewAvailable())
+ return false;
+ cDisplayMenuListView *list = rootView->GetListView();
+ if (!list)
+ return false;
+ list->AddTimersMenuItem(Index, Timer, Current, Selectable);
+ if (state == vsIdle)
+ state = vsMenuUpdate;
+ return true;
+}
+
+bool cSDDisplayMenu::SetItemChannel(const cChannel *Channel, int Index, bool Current, bool Selectable, bool WithProvider) {
+ if (!doOutput)
+ return true;
+ if (!rootView->SubViewAvailable())
+ return false;
+ cDisplayMenuListView *list = rootView->GetListView();
+ if (!list)
+ return false;
+ list->AddChannelsMenuItem(Index, Channel, WithProvider, Current, Selectable);
+ if (state == vsIdle)
+ state = vsMenuUpdate;
+ return true;
+}
+
+bool cSDDisplayMenu::SetItemRecording(const cRecording *Recording, int Index, bool Current, bool Selectable, int Level, int Total, int New) {
+ if (!doOutput)
+ return true;
+ if (!rootView->SubViewAvailable())
+ return false;
+ cDisplayMenuListView *list = rootView->GetListView();
+ if (!list)
+ return false;
+ list->AddRecordingMenuItem(Index, Recording, Level, Total, New, Current, Selectable);
+ if (state == vsIdle)
+ state = vsMenuUpdate;
+ return true;
+}
+
+void cSDDisplayMenu::SetItem(const char *Text, int Index, bool Current, bool Selectable) {
+ if (!doOutput)
+ return;
+ cDisplayMenuListView *list = rootView->GetListView();
+ if (!list) {
+ return;
+ }
+ eMenuCategory cat = MenuCategory();
+ if (cat == mcMain) {
+ list->AddMainMenuItem(Index, Text, Current, Selectable);
+ } else if (cat == mcSetup) {
+ list->AddSetupMenuItem(Index, Text, Current, Selectable);
+ } else {
+ string *tabTexts = new string[MaxTabs];
+ for (int i=0; i<MaxTabs; i++) {
+ const char *s = GetTabbedText(Text, i);
+ if (s) {
+ tabTexts[i] = s;
+ } else {
+ tabTexts[i] = "";
+ }
+ }
+ list->AddDefaultMenuItem(Index, tabTexts, Current, Selectable);
+ SetEditableWidth( rootView->GetListViewWidth() / 2);
+ }
+ if (state == vsIdle)
+ state = vsMenuUpdate;
+}
+
+void cSDDisplayMenu::SetTabs(int Tab1, int Tab2, int Tab3, int Tab4, int Tab5) {
+ if (!doOutput)
+ return;
+ rootView->SetTabs(Tab1, Tab2, Tab3, Tab4, Tab5);
+}
+
+int cSDDisplayMenu::GetTextAreaWidth(void) const {
+ int areaWidth = rootView->GetTextAreaWidth();
+ return areaWidth;
+}
+
+const cFont *cSDDisplayMenu::GetTextAreaFont(bool FixedFont) const {
+ return NULL;
+}
+
+void cSDDisplayMenu::SetScrollbar(int Total, int Offset) {
+ if (!doOutput)
+ return;
+ rootView->RenderMenuScrollBar(Total, Offset);
+}
+
+void cSDDisplayMenu::SetEvent(const cEvent *Event) {
+ if (!doOutput)
+ return;
+ rootView->SetDetailedViewEvent(Event);
+ state = vsMenuDetail;
+}
+
+void cSDDisplayMenu::SetRecording(const cRecording *Recording) {
+ if (!doOutput)
+ return;
+ rootView->SetDetailedViewRecording(Recording);
+ state = vsMenuDetail;
+}
+
+void cSDDisplayMenu::SetText(const char *Text, bool FixedFont) {
+ if (!doOutput)
+ return;
+ rootView->SetDetailedViewText(Text);
+ state = vsMenuDetail;
+}
+
+void cSDDisplayMenu::Flush(void) {
+ if (!doOutput)
+ return;
+ if (state == vsInit) {
+ rootView->Start();
+ rootView->RenderMenuItems();
+ rootView->DoFlush();
+ } else if (state == vsMenuInit) {
+ rootView->Render();
+ rootView->DoFlush();
+ rootView->RenderMenuItems();
+ rootView->DoFlush();
+ } else if (state == vsMenuUpdate) {
+ rootView->RenderMenuItems();
+ rootView->DoFlush();
+ } else if (state == vsMenuDetail) {
+ rootView->Render();
+ rootView->DoFlush();
+ rootView->RenderDetailView();
+ rootView->DoFlush();
+ } else {
+ if (rootView->RenderDynamicElements())
+ rootView->DoFlush();
+ }
+ state = vsIdle;
+}
diff --git a/displaymenu.h b/displaymenu.h
new file mode 100644
index 0000000..58bc9c9
--- /dev/null
+++ b/displaymenu.h
@@ -0,0 +1,48 @@
+#ifndef __DISPLAYMENU_H
+#define __DISPLAYMENU_H
+
+#include "designer.h"
+#include "libtemplate/template.h"
+#include "views/displaymenurootview.h"
+
+enum eViewState {
+ vsInit,
+ vsMenuInit,
+ vsMenuUpdate,
+ vsMenuDetail,
+ vsIdle
+};
+
+class cSDDisplayMenu : public cSkinDisplayMenu {
+private:
+ cDisplayMenuRootView *rootView;
+ eViewState state;
+ bool doOutput;
+protected:
+ int Tab(int n);
+public:
+ cSDDisplayMenu(cTemplate *menuTemplate);
+ virtual ~cSDDisplayMenu();
+ virtual void Scroll(bool Up, bool Page);
+ virtual int MaxItems(void);
+ virtual void Clear(void);
+ virtual void SetMenuCategory(eMenuCategory MenuCat);
+ virtual void SetTitle(const char *Title);
+ virtual void SetButtons(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
+ virtual void SetMessage(eMessageType Type, const char *Text);
+ virtual void SetItem(const char *Text, int Index, bool Current, bool Selectable);
+ virtual bool SetItemEvent(const cEvent *Event, int Index, bool Current, bool Selectable, const cChannel *Channel, bool WithDate, eTimerMatch TimerMatch);
+ virtual bool SetItemTimer(const cTimer *Timer, int Index, bool Current, bool Selectable);
+ virtual bool SetItemChannel(const cChannel *Channel, int Index, bool Current, bool Selectable, bool WithProvider);
+ virtual bool SetItemRecording(const cRecording *Recording, int Index, bool Current, bool Selectable, int Level, int Total, int New);
+ virtual void SetScrollbar(int Total, int Offset);
+ virtual void SetEvent(const cEvent *Event);
+ virtual void SetRecording(const cRecording *Recording);
+ virtual void SetText(const char *Text, bool FixedFont);
+ virtual void Flush(void);
+ virtual void SetTabs(int Tab1, int Tab2 = 0, int Tab3 = 0, int Tab4 = 0, int Tab5 = 0);
+ virtual int GetTextAreaWidth(void) const;
+ virtual const cFont *GetTextAreaFont(bool FixedFont) const;
+};
+
+#endif //__DISPLAYMENU_H
diff --git a/displaymessage.c b/displaymessage.c
new file mode 100644
index 0000000..f64a898
--- /dev/null
+++ b/displaymessage.c
@@ -0,0 +1,43 @@
+#include "displaymessage.h"
+
+cSDDisplayMessage::cSDDisplayMessage(cTemplate *messageTemplate) {
+ doOutput = true;
+ initial = true;
+ if (!messageTemplate) {
+ doOutput = false;
+ esyslog("skindesigner: displayMessage no valid template - aborting");
+ return;
+ }
+ messageView = new cDisplayMessageView(messageTemplate->GetRootView());
+ if (!messageView->createOsd()) {
+ doOutput = false;
+ return;
+ }
+ messageView->DrawBackground();
+}
+
+cSDDisplayMessage::~cSDDisplayMessage() {
+ if (!doOutput)
+ return;
+ delete messageView;
+}
+
+void cSDDisplayMessage::SetMessage(eMessageType Type, const char *Text) {
+ if (!doOutput)
+ return;
+ if (!Text)
+ return;
+ messageView->DrawMessage(Type, Text);
+}
+
+
+void cSDDisplayMessage::Flush(void) {
+ if (!doOutput)
+ return;
+ if (initial) {
+ messageView->DoFadeIn();
+ initial = false;
+ } else {
+ messageView->Flush();
+ }
+}
diff --git a/displaymessage.h b/displaymessage.h
new file mode 100644
index 0000000..f1fd01b
--- /dev/null
+++ b/displaymessage.h
@@ -0,0 +1,22 @@
+#ifndef __DISPLAYMESSAGE_H
+#define __DISPLAYMESSAGE_H
+
+#include <vdr/thread.h>
+#include <vdr/skins.h>
+#include "config.h"
+#include "libtemplate/template.h"
+#include "views/displaymessageview.h"
+
+class cSDDisplayMessage : public cSkinDisplayMessage {
+private:
+ cDisplayMessageView *messageView;
+ bool doOutput;
+ bool initial;
+public:
+ cSDDisplayMessage(cTemplate *messageTemplate);
+ virtual ~cSDDisplayMessage();
+ virtual void SetMessage(eMessageType Type, const char *Text);
+ virtual void Flush(void);
+};
+
+#endif //__DISPLAYMESSAGE_H \ No newline at end of file
diff --git a/displayreplay.c b/displayreplay.c
new file mode 100644
index 0000000..53a43d8
--- /dev/null
+++ b/displayreplay.c
@@ -0,0 +1,131 @@
+#define __STL_CONFIG_H
+#include "displayreplay.h"
+
+cSDDisplayReplay::cSDDisplayReplay(cTemplate *replayTemplate, bool ModeOnly) {
+ doOutput = true;
+ initial = true;
+ modeOnly = ModeOnly;
+ numMarksLast = 0;
+ lastMarks = NULL;
+ if (!replayTemplate) {
+ doOutput = false;
+ esyslog("skindesigner: displayReplay no valid template - aborting");
+ return;
+ }
+ replayView = new cDisplayReplayView(replayTemplate->GetRootView());
+ if (!replayView->createOsd()) {
+ doOutput = false;
+ return;
+ }
+ replayView->DrawBackground(modeOnly);
+}
+
+cSDDisplayReplay::~cSDDisplayReplay() {
+ if (!doOutput)
+ return;
+ delete replayView;
+ if (lastMarks) {
+ delete[] lastMarks;
+ }
+}
+
+void cSDDisplayReplay::SetRecording(const cRecording *Recording) {
+ if (!doOutput)
+ return;
+ replayView->DrawTitle(Recording);
+ replayView->DrawRecordingInformation(Recording);
+ replayView->DrawScraperContent(Recording);
+}
+
+void cSDDisplayReplay::SetMode(bool Play, bool Forward, int Speed) {
+ if (!doOutput)
+ return;
+ replayView->DrawControlIcons(Play, Forward, Speed, modeOnly);
+}
+
+void cSDDisplayReplay::SetProgress(int Current, int Total) {
+ if (!doOutput)
+ return;
+ replayView->DrawProgressBar(Current, Total);
+ if (MarksChanged()) {
+ replayView->DrawMarks(marks, Total);
+ }
+}
+
+void cSDDisplayReplay::SetCurrent(const char *Current) {
+ if (!doOutput)
+ return;
+ replayView->DrawCurrent(Current);
+}
+
+void cSDDisplayReplay::SetTotal(const char *Total) {
+ if (!doOutput)
+ return;
+ replayView->DrawTotal(Total);
+}
+
+void cSDDisplayReplay::SetJump(const char *Jump) {
+ if (!doOutput)
+ return;
+ replayView->DrawJump(Jump);
+}
+
+void cSDDisplayReplay::SetMessage(eMessageType Type, const char *Text) {
+ if (!doOutput)
+ return;
+ replayView->DrawMessage(Type, Text);
+}
+
+void cSDDisplayReplay::Flush(void) {
+ if (!doOutput)
+ return;
+ replayView->DrawDate(modeOnly);
+ if (initial) {
+ replayView->DoFadeIn();
+ initial = false;
+ } else {
+ replayView->Flush();
+ }
+}
+
+/****************************************************************************************
+* Private Functions
+*****************************************************************************************/
+
+bool cSDDisplayReplay::MarksChanged(void) {
+ if (!marks)
+ return false;
+ int numMarks = marks->Count();
+ if (numMarks != numMarksLast) {
+ RememberMarks();
+ return true;
+ }
+ if (!lastMarks)
+ return false;
+ int i=0;
+ for (const cMark *m = marks->First(); m; m = marks->Next(m)) {
+ if (m->Position() != lastMarks[i]) {
+ RememberMarks();
+ return true;
+ }
+ i++;
+ }
+ return false;
+}
+
+void cSDDisplayReplay::RememberMarks(void) {
+ if (!marks)
+ return;
+ numMarksLast = marks->Count();
+ if (numMarksLast < 1)
+ return;
+ if (lastMarks) {
+ delete[] lastMarks;
+ }
+ lastMarks = new int[numMarksLast];
+ int i=0;
+ for (const cMark *m = marks->First(); m; m = marks->Next(m)) {
+ lastMarks[i] = m->Position();
+ i++;
+ }
+}
diff --git a/displayreplay.h b/displayreplay.h
new file mode 100644
index 0000000..a63c8d8
--- /dev/null
+++ b/displayreplay.h
@@ -0,0 +1,34 @@
+#ifndef __DISPLAYREPLAY_H
+#define __DISPLAYREPLAY_H
+
+#include <vdr/skins.h>
+#include <vdr/thread.h>
+#include "config.h"
+#include "libtemplate/template.h"
+#include "views/displayreplayview.h"
+
+class cSDDisplayReplay : public cSkinDisplayReplay {
+private:
+ cDisplayReplayView *replayView;
+ bool initial;
+ bool doOutput;
+ bool modeOnly;
+ int numMarksLast;
+ int *lastMarks;
+ bool MarksChanged(void);
+ void RememberMarks(void);
+public:
+ cSDDisplayReplay(cTemplate *replayTemplate, bool ModeOnly);
+ virtual ~cSDDisplayReplay();
+ virtual void SetRecording(const cRecording *Recording);
+ virtual void SetTitle(const char *Title) {};
+ virtual void SetMode(bool Play, bool Forward, int Speed);
+ virtual void SetProgress(int Current, int Total);
+ virtual void SetCurrent(const char *Current);
+ virtual void SetTotal(const char *Total);
+ virtual void SetJump(const char *Jump);
+ virtual void SetMessage(eMessageType Type, const char *Text);
+ virtual void Flush(void);
+};
+
+#endif //__DISPLAYREPLAY_H \ No newline at end of file
diff --git a/displaytracks.c b/displaytracks.c
new file mode 100644
index 0000000..6316221
--- /dev/null
+++ b/displaytracks.c
@@ -0,0 +1,58 @@
+#include "displaytracks.h"
+
+
+cSDDisplayTracks::cSDDisplayTracks(cTemplate *audiotracksTemplate, const char *Title, int NumTracks, const char * const *Tracks) {
+ initial = true;
+ numTracks = NumTracks;
+ doOutput = true;
+ currentTrack = 0;
+ menuTitle = Title;
+ if (!audiotracksTemplate) {
+ esyslog("skindesigner: displayTracks no valid template - aborting");
+ doOutput = false;
+ return;
+ }
+ tracksView = new cDisplayAudiotracksView(NumTracks, audiotracksTemplate->GetRootView());
+ if (!tracksView->createOsd()) {
+ doOutput = false;
+ return;
+ }
+ tracksView->DrawBackground();
+
+ cDisplayMenuListView *list = tracksView->GetListView();
+ if (list) {
+ for (int i = 0; i < NumTracks; i++) {
+ list->AddTracksMenuItem(i, Tracks[i], (i==currentTrack)?true:false, true);
+ }
+ }
+}
+
+cSDDisplayTracks::~cSDDisplayTracks() {
+ if (!doOutput)
+ return;
+ delete tracksView;
+}
+
+void cSDDisplayTracks::SetTrack(int Index, const char * const *Tracks) {
+ cDisplayMenuListView *list = tracksView->GetListView();
+ if (list) {
+ list->AddTracksMenuItem(currentTrack, Tracks[currentTrack], false, true);
+ list->AddTracksMenuItem(Index, Tracks[Index], true, true);
+ currentTrack = Index;
+ }
+}
+
+void cSDDisplayTracks::SetAudioChannel(int AudioChannel) {
+ tracksView->DrawHeader(menuTitle, AudioChannel);
+}
+
+void cSDDisplayTracks::Flush(void) {
+ if (!doOutput)
+ return;
+ if (initial) {
+ tracksView->DoFadeIn();
+ }
+ initial = false;
+ tracksView->RenderMenuItems();
+ tracksView->Flush();
+}
diff --git a/displaytracks.h b/displaytracks.h
new file mode 100644
index 0000000..4dd978c
--- /dev/null
+++ b/displaytracks.h
@@ -0,0 +1,27 @@
+#ifndef __DISPLAYTRACKS_H
+#define __DISPLAYTRACKS_H
+
+#include <vdr/skins.h>
+#include <vdr/thread.h>
+#include "config.h"
+#include "libtemplate/template.h"
+#include "views/displayaudiotracksview.h"
+
+class cSDDisplayTracks : public cSkinDisplayTracks {
+private:
+ cDisplayAudiotracksView *tracksView;
+ bool initial;
+ int numTracks;
+ bool doOutput;
+ int currentTrack;
+ const char *menuTitle;
+public:
+ cSDDisplayTracks(cTemplate *audiotracksTemplate, const char *Title, int NumTracks, const char * const *Tracks);
+ virtual ~cSDDisplayTracks();
+ virtual void SetTrack(int Index, const char * const *Tracks);
+ virtual void SetAudioChannel(int AudioChannel);
+ virtual void Flush(void);
+};
+
+
+#endif //__DISPLAYTRACKS_H \ No newline at end of file
diff --git a/displayvolume.c b/displayvolume.c
new file mode 100644
index 0000000..5efa32f
--- /dev/null
+++ b/displayvolume.c
@@ -0,0 +1,43 @@
+#include "displayvolume.h"
+
+#include "config.h"
+#include "libcore/helpers.h"
+
+cSDDisplayVolume::cSDDisplayVolume(cTemplate *volumeTemplate) {
+ doOutput = true;
+ initial = true;
+ if (!volumeTemplate) {
+ doOutput = false;
+ esyslog("skindesigner: displayVolume no valid template - aborting");
+ return;
+ }
+ volumeView = new cDisplayVolumeView(volumeTemplate->GetRootView());
+ if (!volumeView->createOsd()) {
+ doOutput = false;
+ } else {
+ volumeView->DrawBackground();
+ }
+}
+
+cSDDisplayVolume::~cSDDisplayVolume() {
+ if (!doOutput)
+ return;
+ delete volumeView;
+}
+
+void cSDDisplayVolume::SetVolume(int Current, int Total, bool Mute) {
+ if (!doOutput)
+ return;
+ volumeView->DrawVolume(Current, Total, Mute);
+}
+
+void cSDDisplayVolume::Flush(void) {
+ if (!doOutput)
+ return;
+ if (initial) {
+ volumeView->DoFadeIn();
+ initial = false;
+ } else {
+ volumeView->Flush();
+ }
+}
diff --git a/displayvolume.h b/displayvolume.h
new file mode 100644
index 0000000..1bfc877
--- /dev/null
+++ b/displayvolume.h
@@ -0,0 +1,21 @@
+#ifndef __DISPLAYVOLUME_H
+#define __DISPLAYVOLUME_H
+
+#include <vdr/skins.h>
+#include "config.h"
+#include "libtemplate/template.h"
+#include "views/displayvolumeview.h"
+
+class cSDDisplayVolume : public cSkinDisplayVolume {
+private:
+ cDisplayVolumeView *volumeView;
+ bool doOutput;
+ bool initial;
+public:
+ cSDDisplayVolume(cTemplate *volumeTemplate);
+ virtual ~cSDDisplayVolume();
+ virtual void SetVolume(int Current, int Total, bool Mute);
+ virtual void Flush(void);
+};
+
+#endif //__DISPLAYVOLUME_H \ No newline at end of file
diff --git a/fonts/VDROpenSans/Apache License.txt b/fonts/VDROpenSans/Apache License.txt
new file mode 100644
index 0000000..989e2c5
--- /dev/null
+++ b/fonts/VDROpenSans/Apache License.txt
@@ -0,0 +1,201 @@
+Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License. \ No newline at end of file
diff --git a/fonts/VDROpenSans/VDROpenSans-Bold.ttf b/fonts/VDROpenSans/VDROpenSans-Bold.ttf
new file mode 100644
index 0000000..9d51f27
--- /dev/null
+++ b/fonts/VDROpenSans/VDROpenSans-Bold.ttf
Binary files differ
diff --git a/fonts/VDROpenSans/VDROpenSans-BoldItalic.ttf b/fonts/VDROpenSans/VDROpenSans-BoldItalic.ttf
new file mode 100644
index 0000000..61fc899
--- /dev/null
+++ b/fonts/VDROpenSans/VDROpenSans-BoldItalic.ttf
Binary files differ
diff --git a/fonts/VDROpenSans/VDROpenSans-ExtraBold.ttf b/fonts/VDROpenSans/VDROpenSans-ExtraBold.ttf
new file mode 100644
index 0000000..3701480
--- /dev/null
+++ b/fonts/VDROpenSans/VDROpenSans-ExtraBold.ttf
Binary files differ
diff --git a/fonts/VDROpenSans/VDROpenSans-ExtraBoldItalic.ttf b/fonts/VDROpenSans/VDROpenSans-ExtraBoldItalic.ttf
new file mode 100644
index 0000000..b760f90
--- /dev/null
+++ b/fonts/VDROpenSans/VDROpenSans-ExtraBoldItalic.ttf
Binary files differ
diff --git a/fonts/VDROpenSans/VDROpenSans-Italic.ttf b/fonts/VDROpenSans/VDROpenSans-Italic.ttf
new file mode 100644
index 0000000..4fc4fe1
--- /dev/null
+++ b/fonts/VDROpenSans/VDROpenSans-Italic.ttf
Binary files differ
diff --git a/fonts/VDROpenSans/VDROpenSans-Light.ttf b/fonts/VDROpenSans/VDROpenSans-Light.ttf
new file mode 100644
index 0000000..4806a9c
--- /dev/null
+++ b/fonts/VDROpenSans/VDROpenSans-Light.ttf
Binary files differ
diff --git a/fonts/VDROpenSans/VDROpenSans-LightItalic.ttf b/fonts/VDROpenSans/VDROpenSans-LightItalic.ttf
new file mode 100644
index 0000000..4380547
--- /dev/null
+++ b/fonts/VDROpenSans/VDROpenSans-LightItalic.ttf
Binary files differ
diff --git a/fonts/VDROpenSans/VDROpenSans-Regular.ttf b/fonts/VDROpenSans/VDROpenSans-Regular.ttf
new file mode 100644
index 0000000..eaa8273
--- /dev/null
+++ b/fonts/VDROpenSans/VDROpenSans-Regular.ttf
Binary files differ
diff --git a/fonts/VDROpenSans/VDROpenSans-Semibold.ttf b/fonts/VDROpenSans/VDROpenSans-Semibold.ttf
new file mode 100644
index 0000000..2394fe1
--- /dev/null
+++ b/fonts/VDROpenSans/VDROpenSans-Semibold.ttf
Binary files differ
diff --git a/fonts/VDROpenSans/VDROpenSans-SemiboldItalic.ttf b/fonts/VDROpenSans/VDROpenSans-SemiboldItalic.ttf
new file mode 100644
index 0000000..1afcda3
--- /dev/null
+++ b/fonts/VDROpenSans/VDROpenSans-SemiboldItalic.ttf
Binary files differ
diff --git a/libcore/fontmanager.c b/libcore/fontmanager.c
new file mode 100644
index 0000000..1dcba44
--- /dev/null
+++ b/libcore/fontmanager.c
@@ -0,0 +1,174 @@
+#include "fontmanager.h"
+#include "../config.h"
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+using namespace std;
+
+cMutex cFontManager::mutex;
+
+cFontManager::cFontManager() {
+}
+
+cFontManager::~cFontManager() {
+ DeleteFonts();
+}
+
+void cFontManager::CacheFonts(cTemplate *tpl) {
+ cMutexLock MutexLock(&mutex);
+
+ vector< pair<string, int> > usedFonts = tpl->GetUsedFonts();
+
+ cStringList availableFonts;
+ cFont::GetAvailableFontNames(&availableFonts);
+
+ for (vector< pair<string, int> >::iterator ft = usedFonts.begin(); ft != usedFonts.end(); ft++) {
+ string fontName = ft->first;
+ int fontSize = ft->second;
+ if (fontSize < 1) {
+ continue;
+ }
+
+ int fontAvailable = availableFonts.Find(fontName.c_str());
+ if (fontAvailable == -1) {
+ esyslog("skindesigner: font %s not available, skipping", fontName.c_str());
+ continue;
+ }
+
+ InsertFont(fontName, fontSize);
+ }
+}
+
+void cFontManager::Debug(void) {
+ dsyslog("skindesigner: fontmanager fonts available:");
+ for (map < string, map< int, cFont* > >::iterator fts = fonts.begin(); fts != fonts.end(); fts++) {
+ dsyslog("skindesigner: FontName %s", fts->first.c_str());
+ for (map<int, cFont*>::iterator ftSizes = (fts->second).begin(); ftSizes != (fts->second).end(); ftSizes++) {
+ int confHeight = ftSizes->first;
+ int realHeight = (ftSizes->second)->Height();
+ dsyslog("skindesigner: fontSize %d, fontHeight %d, ratio %f", confHeight, realHeight, (double)confHeight / (double)realHeight);
+ }
+ }
+}
+
+void cFontManager::ListAvailableFonts(void) {
+ cStringList availableFonts;
+ cFont::GetAvailableFontNames(&availableFonts);
+ int numFonts = availableFonts.Size();
+ esyslog("skindesigner: %d Fonts available:", numFonts);
+ for (int i=0; i<numFonts; i++) {
+ esyslog("skindesigner: font %d: %s", i, availableFonts[i]);
+ }
+}
+
+void cFontManager::DeleteFonts() {
+ cMutexLock MutexLock(&mutex);
+ for(map<string, map<int,cFont*> >::iterator it = fonts.begin(); it != fonts.end(); it++) {
+ for(map<int,cFont*>::iterator it2 = (it->second).begin(); it2 != (it->second).end(); it2++) {
+ delete it2->second;
+ }
+ }
+ fonts.clear();
+}
+
+int cFontManager::Width(string fontName, int fontSize, const char *text) {
+ cMutexLock MutexLock(&mutex);
+ if (!text)
+ return 0;
+ cFont *font = GetFont(fontName, fontSize);
+ //if not already cached, load it new
+ if (!font)
+ InsertFont(fontName, fontSize);
+ font = GetFont(fontName, fontSize);
+ if (!font)
+ return 0;
+ int width = font->Width(text);
+ return width;
+}
+
+int cFontManager::Height(string fontName, int fontSize) {
+ cMutexLock MutexLock(&mutex);
+ cFont *font = GetFont(fontName, fontSize);
+ //if not already cached, load it new
+ if (!font)
+ InsertFont(fontName, fontSize);
+ font = GetFont(fontName, fontSize);
+ if (!font)
+ return 0;
+ return font->Height();
+}
+
+cFont *cFontManager::Font(string fontName, int fontSize) {
+ cMutexLock MutexLock(&mutex);
+ cFont *font = GetFont(fontName, fontSize);
+ //if not already cached, load it new
+ if (!font)
+ InsertFont(fontName, fontSize);
+ font = GetFont(fontName, fontSize);
+ return font;
+}
+
+/********************************************************************************
+* Private Functions
+********************************************************************************/
+
+cFont *cFontManager::CreateFont(string name, int size) {
+ cMutexLock MutexLock(&mutex);
+ cFont *fontTmp = cFont::CreateFont(name.c_str(), size);
+ if (!fontTmp)
+ fontTmp = cFont::CreateFont(Setup.FontOsd, size);
+ int realHeight = fontTmp->Height();
+ delete fontTmp;
+ cFont *font = cFont::CreateFont(name.c_str(), (double)size / (double)realHeight * (double)size);
+ if (!font)
+ font = cFont::CreateFont(Setup.FontOsd, (double)size / (double)realHeight * (double)size);
+ return font;
+}
+
+void cFontManager::InsertFont(string name, int size) {
+ cFont *newFont = CreateFont(name, size);
+ if (!newFont)
+ return;
+ map < string, map< int, cFont* > >::iterator hit = fonts.find(name);
+ if (hit != fonts.end()) {
+ (hit->second).insert(pair<int, cFont*>(size, newFont));
+ } else {
+ map<int, cFont*> fontsizes;
+ fontsizes.insert(pair<int, cFont*>(size, newFont));
+ fonts.insert(pair<string, map<int, cFont*> >(name, fontsizes));
+ }
+}
+
+cFont *cFontManager::GetFont(string name, int size) {
+ map< string, map<int,cFont*> >::iterator hitName = fonts.find(name);
+ if (hitName == fonts.end())
+ return NULL;
+ map<int,cFont*>::iterator hitSize = (hitName->second).find(size);
+ if (hitSize == (hitName->second).end())
+ return NULL;
+ return hitSize->second;
+}
+
+int cFontManager::GetFontHeight(const char *name, int height, int charWidth) {
+ FT_Library library;
+ FT_Face face;
+ cString fontFileName = cFont::GetFontFileName(name);
+
+ int descender = 0;
+ int y_ppem = 0;
+ int error = FT_Init_FreeType(&library);
+ if (error) return 0;
+ error = FT_New_Face(library, fontFileName, 0, &face);
+ if (error) return 0;
+ error = FT_Set_Char_Size(face, charWidth * 64, height * 64, 0, 0);
+ if (error) return 0;
+
+ descender = face->size->metrics.descender/64;
+ y_ppem = face->size->metrics.y_ppem;
+ int realHeight = y_ppem + descender;
+
+ FT_Done_Face(face);
+ FT_Done_FreeType(library);
+
+ return realHeight;
+}
diff --git a/libcore/fontmanager.h b/libcore/fontmanager.h
new file mode 100644
index 0000000..7067dfc
--- /dev/null
+++ b/libcore/fontmanager.h
@@ -0,0 +1,35 @@
+#ifndef __FONTMANAGER_H
+#define __FONTMANAGER_H
+
+#include <string>
+#include <map>
+#include <vector>
+#include <vdr/skins.h>
+
+#include "../libtemplate/template.h"
+
+using namespace std;
+
+class cFontManager {
+ private:
+ static cMutex mutex;
+ map < string, map< int, cFont* > > fonts;
+ cFont *CreateFont(string name, int size);
+ void InsertFont(string name, int size);
+ cFont *GetFont(string name, int size);
+ int GetFontHeight(const char *name, int height, int charWidth = 0);
+ public:
+ cFontManager();
+ ~cFontManager();
+ void Lock(void) { mutex.Lock(); };
+ void Unlock(void) { mutex.Unlock(); };
+ void CacheFonts(cTemplate *tpl);
+ void DeleteFonts(void);
+ int Width(string fontName, int fontSize, const char *text);
+ int Height(string fontName, int fontSize);
+ cFont *Font(string fontName, int fontSize);
+ void Debug(void);
+ void ListAvailableFonts(void);
+};
+
+#endif //__FONTMANAGER_H \ No newline at end of file
diff --git a/libcore/helpers.c b/libcore/helpers.c
new file mode 100644
index 0000000..81880a0
--- /dev/null
+++ b/libcore/helpers.c
@@ -0,0 +1,155 @@
+#include <string>
+#include <sstream>
+#include <vector>
+#include "helpers.h"
+#include <vdr/skins.h>
+
+cPlugin *GetScraperPlugin(void) {
+ static cPlugin *pScraper = cPluginManager::GetPlugin("scraper2vdr");
+ if( !pScraper ) // if it doesn't exit, try tvscraper
+ pScraper = cPluginManager::GetPlugin("tvscraper");
+ return pScraper;
+}
+
+cSize ScaleToFit(int widthMax, int heightMax, int widthOriginal, int heightOriginal) {
+ int width = 1;
+ int height = 1;
+
+ if ((widthMax == 0)||(heightMax==0)||(widthOriginal==0)||(heightOriginal==0))
+ return cSize(width, height);
+
+ if ((widthOriginal <= widthMax) && (heightOriginal <= heightMax)) {
+ width = widthOriginal;
+ height = heightOriginal;
+ } else if ((widthOriginal > widthMax) && (heightOriginal <= heightMax)) {
+ width = widthMax;
+ height = (double)width/(double)widthOriginal * heightOriginal;
+ } else if ((widthOriginal <= widthMax) && (heightOriginal > heightMax)) {
+ height = heightMax;
+ width = (double)height/(double)heightOriginal * widthOriginal;
+ } else {
+ width = widthMax;
+ height = (double)width/(double)widthOriginal * heightOriginal;
+ if (height > heightMax) {
+ height = heightMax;
+ width = (double)height/(double)heightOriginal * widthOriginal;
+ }
+ }
+ return cSize(width, height);
+}
+
+int Minimum(int a, int b, int c, int d, int e, int f) {
+ int min = a;
+ if (b < min) min = b;
+ if (c < min) min = c;
+ if (d < min) min = d;
+ if (e < min) min = e;
+ if (f < min) min = f;
+ return min;
+}
+
+string CutText(string &text, int width, string fontName, int fontSize) {
+ if (width <= fontManager->Font(fontName, fontSize)->Size())
+ return text.c_str();
+ cTextWrapper twText;
+ twText.Set(text.c_str(), fontManager->Font(fontName, fontSize), width);
+ string cuttedTextNative = twText.GetLine(0);
+ stringstream sstrText;
+ sstrText << cuttedTextNative << "...";
+ string cuttedText = sstrText.str();
+ int actWidth = fontManager->Width(fontName, fontSize, cuttedText.c_str());
+ if (actWidth > width) {
+ int overlap = actWidth - width;
+ int charWidth = fontManager->Width(fontName, fontSize, ".");
+ if (charWidth == 0)
+ charWidth = 1;
+ int cutChars = overlap / charWidth;
+ if (cutChars > 0) {
+ cuttedTextNative = cuttedTextNative.substr(0, cuttedTextNative.length() - cutChars);
+ stringstream sstrText2;
+ sstrText2 << cuttedTextNative << "...";
+ cuttedText = sstrText2.str();
+ }
+ }
+ return cuttedText;
+}
+
+
+string StrToLowerCase(string str) {
+ string lowerCase = str;
+ const int length = lowerCase.length();
+ for(int i=0; i < length; ++i) {
+ lowerCase[i] = std::tolower(lowerCase[i]);
+ }
+ return lowerCase;
+}
+
+bool isNumber(const string& s) {
+ string::const_iterator it = s.begin();
+ while (it != s.end() && std::isdigit(*it)) ++it;
+ return !s.empty() && it == s.end();
+}
+
+bool FileExists(const string &path, const string &name, const string &ext) {
+ stringstream fileName;
+ fileName << path << name << "." << ext;
+ struct stat buffer;
+ return (stat (fileName.str().c_str(), &buffer) == 0);
+}
+
+bool FirstFileInFolder(string &path, string &extension, string &fileName) {
+ DIR *folder = NULL;
+ struct dirent *file;
+ folder = opendir(path.c_str());
+ if (!folder)
+ return false;
+ while (file = readdir(folder)) {
+ if (endswith(file->d_name, extension.c_str())) {
+ string currentFileName = file->d_name;
+ int strlength = currentFileName.size();
+ if (strlength < 8)
+ continue;
+ fileName = currentFileName;
+ return true;
+ }
+ }
+ return false;
+}
+
+// split: receives a char delimiter; returns a vector of strings
+// By default ignores repeated delimiters, unless argument rep == 1.
+vector<string>& splitstring::split(char delim, int rep) {
+ if (!flds.empty()) flds.clear(); // empty vector if necessary
+ string work = data();
+ string buf = "";
+ int i = 0;
+ while (i < work.length()) {
+ if (work[i] != delim)
+ buf += work[i];
+ else if (rep == 1) {
+ flds.push_back(buf);
+ buf = "";
+ } else if (buf.length() > 0) {
+ flds.push_back(buf);
+ buf = "";
+ }
+ i++;
+ }
+ if (!buf.empty())
+ flds.push_back(buf);
+ return flds;
+}
+
+cStopWatch::cStopWatch(void) {
+ start = cTimeMs::Now();
+ last = start;
+}
+
+void cStopWatch::Report(const char* message) {
+ dsyslog("skindesigner: %s - needed %d ms", message, (int)(cTimeMs::Now() - last));
+ last = cTimeMs::Now();
+}
+
+void cStopWatch::Stop(const char* message) {
+ dsyslog("skindesigner: %s - needed %d ms", message, (int)(cTimeMs::Now() - start));
+}
diff --git a/libcore/helpers.h b/libcore/helpers.h
new file mode 100644
index 0000000..60f3345
--- /dev/null
+++ b/libcore/helpers.h
@@ -0,0 +1,35 @@
+#ifndef __HELPERS_H
+#define __HELPERS_H
+
+#include <vdr/osd.h>
+#include <vdr/plugin.h>
+#include "../config.h"
+
+cPlugin *GetScraperPlugin(void);
+
+cSize ScaleToFit(int widthMax, int heightMax, int widthOriginal, int heightOriginal);
+int Minimum(int a, int b, int c, int d, int e, int f);
+std::string CutText(string &text, int width, string fontName, int fontSize);
+std::string StrToLowerCase(string str);
+bool isNumber(const string& s);
+bool FileExists(const string &path, const string &name, const string &ext);
+bool FirstFileInFolder(string &path, string &extension, string &fileName);
+
+class splitstring : public std::string {
+ std::vector<std::string> flds;
+public:
+ splitstring(const char *s) : std::string(s) { };
+ std::vector<std::string>& split(char delim, int rep=0);
+};
+
+class cStopWatch {
+private:
+ uint64_t start;
+ uint64_t last;
+public:
+ cStopWatch(void);
+ ~cStopWatch(void) {};
+ void Report(const char* message);
+ void Stop(const char* message);
+};
+#endif // __HELPERS_H
diff --git a/libcore/imagecache.c b/libcore/imagecache.c
new file mode 100644
index 0000000..7347c0a
--- /dev/null
+++ b/libcore/imagecache.c
@@ -0,0 +1,389 @@
+#include <string>
+#include <sstream>
+#include <map>
+#include <fstream>
+#include <sys/stat.h>
+#include "imagecache.h"
+#include "../config.h"
+#include "helpers.h"
+
+using namespace Magick;
+
+cMutex cImageCache::mutex;
+
+string cImageCache::items[16] = { "Schedule", "Channels", "Timers", "Recordings", "Setup", "Commands",
+ "OSD", "EPG", "DVB", "LNB", "CAM", "Recording", "Replay", "Miscellaneous", "Plugins", "Restart"};
+
+cImageCache::cImageCache() : cImageMagickWrapper() {
+ tempStaticLogo = NULL;
+}
+
+cImageCache::~cImageCache() {
+ Clear();
+ if (tempStaticLogo) {
+ delete tempStaticLogo;
+ tempStaticLogo = NULL;
+ }
+}
+
+void cImageCache::CacheLogo(int width, int height) {
+ if (config.numLogosPerSizeInitial == 0)
+ return;
+ if (width == 0 || height == 0)
+ return;
+
+ int channelsCached = 0;
+
+ for (const cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) {
+ if (channelsCached >= config.numLogosPerSizeInitial)
+ break;
+ if (channel->GroupSep()) {
+ continue;
+ }
+ bool success = LoadLogo(channel);
+ if (success) {
+ channelsCached++;
+ cImage *image = CreateImage(width, height);
+ stringstream logoName;
+ logoName << *channel->GetChannelID().ToString() << "_" << width << "x" << height;
+ std::map<std::string, cImage*>::iterator hit = channelLogoCache.find(logoName.str());
+ if (hit != channelLogoCache.end()) {
+ delete image;
+ return;
+ }
+ channelLogoCache.insert(pair<string, cImage*>(logoName.str(), image));
+ }
+ }
+}
+
+cImage *cImageCache::GetLogo(string channelID, int width, int height) {
+ cMutexLock MutexLock(&mutex);
+
+ stringstream logoName;
+ logoName << channelID << "_" << width << "x" << height;
+
+ std::map<std::string, cImage*>::iterator hit = channelLogoCache.find(logoName.str());
+
+ if (hit != channelLogoCache.end()) {
+ return (cImage*)hit->second;
+ } else {
+ tChannelID chanID = tChannelID::FromString(channelID.c_str());
+ const cChannel *channel = Channels.GetByChannelID(chanID);
+ if (!channel)
+ return NULL;
+ bool success = LoadLogo(channel);
+ if (success) {
+ if (config.limitLogoCache && (channelLogoCache.size() >= config.numLogosMax)) {
+ //logo cache is full, don't cache anymore
+ if (tempStaticLogo) {
+ delete tempStaticLogo;
+ tempStaticLogo = NULL;
+ }
+ tempStaticLogo = CreateImage(width, height);
+ return tempStaticLogo;
+ } else {
+ //add requested logo to cache
+ cImage *image = CreateImage(width, height);
+ channelLogoCache.insert(pair<string, cImage*>(logoName.str(), image));
+ hit = channelLogoCache.find(logoName.str());
+ if (hit != channelLogoCache.end()) {
+ return (cImage*)hit->second;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+cImage *cImageCache::GetSeparatorLogo(string name, int width, int height) {
+ cMutexLock MutexLock(&mutex);
+
+ stringstream logoName;
+ logoName << name << "_" << width << "x" << height;
+
+ std::map<std::string, cImage*>::iterator hit = channelLogoCache.find(logoName.str());
+
+ if (hit != channelLogoCache.end()) {
+ return (cImage*)hit->second;
+ } else {
+ bool success = LoadSeparatorLogo(name);
+ if (success) {
+ //add requested logo to cache
+ cImage *image = CreateImage(width, height);
+ channelLogoCache.insert(pair<string, cImage*>(logoName.str(), image));
+ hit = channelLogoCache.find(logoName.str());
+ if (hit != channelLogoCache.end()) {
+ return (cImage*)hit->second;
+ }
+ }
+ }
+ return NULL;
+}
+
+bool cImageCache::LogoExists(string channelID) {
+ tChannelID chanID = tChannelID::FromString(channelID.c_str());
+ const cChannel *channel = Channels.GetByChannelID(chanID);
+ if (!channel)
+ return false;
+ string logoPath = *cString::sprintf("%s%s/logos/", *config.skinPath, Setup.OSDTheme);
+ string logoLower = StrToLowerCase(channel->Name());
+ string logoExt = *config.logoExtension;
+ bool logoExists = FileExists(logoPath, logoLower, logoExt);
+ if (logoExists) {
+ return true;
+ }
+ logoExists = FileExists(logoPath, channelID, logoExt);
+ if (logoExists) {
+ return true;
+ }
+ return false;
+}
+
+bool cImageCache::SeparatorLogoExists(string name) {
+ string separatorPath = *cString::sprintf("%s%s/logos/separatorlogos/", *config.skinPath, Setup.OSDTheme);
+ string nameLower = StrToLowerCase(name.c_str());
+ string logoExt = *config.logoExtension;
+ bool logoExists = FileExists(separatorPath, nameLower, logoExt);
+ if (logoExists) {
+ return true;
+ }
+ return false;
+}
+
+void cImageCache::CacheIcon(eImageType type, string name, int width, int height) {
+ if (width < 1 || width > 1920 || height < 1 || height > 1080)
+ return;
+ bool success = LoadIcon(type, name);
+ if (!success)
+ return;
+ stringstream iconName;
+ iconName << name << "_" << width << "x" << height;
+ cImage *image = CreateImage(width, height, true);
+ iconCache.insert(pair<string, cImage*>(iconName.str(), image));
+}
+
+cImage *cImageCache::GetIcon(eImageType type, string name, int width, int height) {
+ if (width < 1 || width > 1920 || height < 1 || height > 1080)
+ return NULL;
+ cMutexLock MutexLock(&mutex);
+ stringstream iconName;
+ iconName << name << "_" << width << "x" << height;
+ map<string, cImage*>::iterator hit = iconCache.find(iconName.str());
+ if (hit != iconCache.end()) {
+ return (cImage*)hit->second;
+ } else {
+ bool success = LoadIcon(type, name);
+ if (!success)
+ return NULL;
+ cImage *image = CreateImage(width, height, true);
+ iconCache.insert(pair<string, cImage*>(iconName.str(), image));
+ hit = iconCache.find(iconName.str());
+ if (hit != iconCache.end()) {
+ return (cImage*)hit->second;
+ }
+ }
+ return NULL;
+}
+
+string cImageCache::GetIconName(string label) {
+ //check for standard menu entries
+ for (int i=0; i<16; i++) {
+ string s = trVDR(items[i].c_str());
+ if (s == label) {
+ return *cString::sprintf("standardicons/%s", items[i].c_str());
+ }
+ }
+ //check for special main menu entries "stop recording", "stop replay"
+ string stopRecording = skipspace(trVDR(" Stop recording "));
+ string stopReplay = skipspace(trVDR(" Stop replaying"));
+ try {
+ if (label.substr(0, stopRecording.size()) == stopRecording) {
+ return "standardicons/StopRecording";
+ }
+ if (label.substr(0, stopReplay.size()) == stopReplay) {
+ return "standardicons/StopReplay";
+ }
+ } catch (...) {}
+ //check for Plugins
+ for (int i = 0; ; i++) {
+ cPlugin *p = cPluginManager::GetPlugin(i);
+ if (p) {
+ const char *mainMenuEntry = p->MainMenuEntry();
+ if (mainMenuEntry) {
+ string plugMainEntry = mainMenuEntry;
+ try {
+ if (label.substr(0, plugMainEntry.size()) == plugMainEntry) {
+ return *cString::sprintf("pluginicons/%s", p->Name());
+ }
+ } catch (...) {}
+ }
+ } else
+ break;
+ }
+ return *cString::sprintf("customicons/%s", label.c_str());
+}
+
+void cImageCache::CacheSkinpart(string name, int width, int height) {
+ if (width < 1 || width > 1920 || height < 1 || height > 1080)
+ return;
+ bool success = LoadSkinpart(name);
+ if (!success)
+ return;
+ stringstream iconName;
+ iconName << name << "_" << width << "x" << height;
+ cImage *image = CreateImage(width, height, false);
+ skinPartsCache.insert(pair<string, cImage*>(iconName.str(), image));
+}
+
+cImage *cImageCache::GetSkinpart(string name, int width, int height) {
+ if (width < 1 || width > 1920 || height < 1 || height > 1080)
+ return NULL;
+ cMutexLock MutexLock(&mutex);
+ stringstream iconName;
+ iconName << name << "_" << width << "x" << height;
+ map<string, cImage*>::iterator hit = skinPartsCache.find(iconName.str());
+ if (hit != skinPartsCache.end()) {
+ return (cImage*)hit->second;
+ } else {
+ bool success = LoadSkinpart(name);
+ if (!success)
+ return NULL;
+ cImage *image = CreateImage(width, height, false);
+ skinPartsCache.insert(pair<string, cImage*>(iconName.str(), image));
+ hit = skinPartsCache.find(iconName.str());
+ if (hit != skinPartsCache.end()) {
+ return (cImage*)hit->second;
+ }
+ }
+ return NULL;
+}
+
+bool cImageCache::LoadIcon(eImageType type, string name) {
+ bool success = false;
+ cString subdir("");
+ if (type == itMenuIcon)
+ subdir = "menuicons";
+ else if (type == itIcon)
+ subdir = "icons";
+ cString iconPath = cString::sprintf("%s%s/graphics/%s/", *config.skinPath, Setup.OSDTheme, *subdir);
+ success = LoadImage(name, *iconPath, "png");
+ if (success) {
+ return true;
+ }
+ return false;
+}
+
+bool cImageCache::LoadLogo(const cChannel *channel) {
+ if (!channel)
+ return false;
+ cString logoPath = cString::sprintf("%s%s/logos/", *config.skinPath, Setup.OSDTheme);
+ string channelID = StrToLowerCase(*(channel->GetChannelID().ToString()));
+ string logoLower = StrToLowerCase(channel->Name());
+ bool success = false;
+ success = LoadImage(channelID.c_str(), *logoPath, *config.logoExtension);
+ if (success)
+ return true;
+ success = LoadImage(logoLower.c_str(), *logoPath, *config.logoExtension);
+ if (success)
+ return true;
+ return false;
+}
+
+bool cImageCache::LoadSeparatorLogo(string name) {
+ cString separatorPath = cString::sprintf("%s%s/logos/separatorlogos/", *config.skinPath, Setup.OSDTheme);
+ string nameLower = StrToLowerCase(name.c_str());
+ bool success = false;
+ success = LoadImage(nameLower.c_str(), *separatorPath, *config.logoExtension);
+ if (success)
+ return true;
+ return false;
+}
+
+bool cImageCache::LoadSkinpart(string name) {
+ bool success = false;
+ cString iconPath = cString::sprintf("%s%s/graphics/skinparts/", *config.skinPath, Setup.OSDTheme);
+ success = LoadImage(name, *iconPath, "png");
+ if (success) {
+ return true;
+ }
+ return false;
+}
+
+void cImageCache::Clear(void) {
+ for(map<string, cImage*>::const_iterator it = iconCache.begin(); it != iconCache.end(); it++) {
+ cImage *img = (cImage*)it->second;
+ delete img;
+ }
+ iconCache.clear();
+
+ for(map<string, cImage*>::const_iterator it = channelLogoCache.begin(); it != channelLogoCache.end(); it++) {
+ cImage *img = (cImage*)it->second;
+ delete img;
+ }
+ channelLogoCache.clear();
+
+ for(map<std::string, cImage*>::const_iterator it = skinPartsCache.begin(); it != skinPartsCache.end(); it++) {
+ cImage *img = (cImage*)it->second;
+ delete img;
+ }
+ skinPartsCache.clear();
+}
+
+void cImageCache::Debug(bool full) {
+ int sizeIconCache = 0;
+ int numIcons = 0;
+ GetIconCacheSize(numIcons, sizeIconCache);
+ dsyslog("skindesigner: cached %d icons - size %d byte", numIcons, sizeIconCache);
+ if (full) {
+ for(std::map<std::string, cImage*>::const_iterator it = iconCache.begin(); it != iconCache.end(); it++) {
+ string name = it->first;
+ dsyslog("skindesigner: cached icon %s", name.c_str());
+ }
+ }
+
+ int sizeLogoCache = 0;
+ int numLogos = 0;
+ GetLogoCacheSize(numLogos, sizeLogoCache);
+ dsyslog("skindesigner: cached %d logos - size %d byte", numLogos, sizeLogoCache);
+ if (full) {
+ for(std::map<std::string, cImage*>::const_iterator it = channelLogoCache.begin(); it != channelLogoCache.end(); it++) {
+ string name = it->first;
+ dsyslog("skindesigner: cached logo %s", name.c_str());
+ }
+ }
+
+ int sizeSkinpartCache = 0;
+ int numSkinparts = 0;
+ GetSkinpartsCacheSize(numSkinparts, sizeSkinpartCache);
+ dsyslog("skindesigner: cached %d skinparts - size %d byte", numSkinparts, sizeSkinpartCache);
+ if (full) {
+ for(std::map<std::string, cImage*>::const_iterator it = skinPartsCache.begin(); it != skinPartsCache.end(); it++) {
+ string name = it->first;
+ dsyslog("skindesigner: cached skinpart %s", name.c_str());
+ }
+ }
+}
+
+void cImageCache::GetIconCacheSize(int &num, int &size) {
+ num = iconCache.size();
+ for (map<string, cImage*>::iterator icon = iconCache.begin(); icon != iconCache.end(); icon++) {
+ cImage* img = icon->second;
+ size += img->Width() * img->Height() * sizeof(tColor);
+ }
+}
+
+void cImageCache::GetLogoCacheSize(int &num, int &size) {
+ num = channelLogoCache.size();
+ for (map<string, cImage*>::iterator logo = channelLogoCache.begin(); logo != channelLogoCache.end(); logo++) {
+ cImage* img = logo->second;
+ size += img->Width() * img->Height() * sizeof(tColor);
+ }
+}
+
+void cImageCache::GetSkinpartsCacheSize(int &num, int &size) {
+ num = skinPartsCache.size();
+ for (map<string, cImage*>::iterator skinpart = skinPartsCache.begin(); skinpart != skinPartsCache.end(); skinpart++) {
+ cImage* img = skinpart->second;
+ size += img->Width() * img->Height() * sizeof(tColor);
+ }
+}
diff --git a/libcore/imagecache.h b/libcore/imagecache.h
new file mode 100644
index 0000000..9e700bf
--- /dev/null
+++ b/libcore/imagecache.h
@@ -0,0 +1,53 @@
+#ifndef __NOPACITY_IMAGECACHE_H
+#define __NOPACITY_IMAGECACHE_H
+
+#define X_DISPLAY_MISSING
+
+#include <vdr/osd.h>
+#include <vdr/skins.h>
+#include <Magick++.h>
+#include <vector>
+#include "imagemagickwrapper.h"
+#include "../libtemplate/templatefunction.h"
+
+using namespace Magick;
+
+class cImageCache : public cImageMagickWrapper {
+public:
+ cImageCache();
+ ~cImageCache();
+ void Lock(void) { mutex.Lock(); }
+ void Unlock(void) { mutex.Unlock(); }
+ //channel logos
+ void CacheLogo(int width, int height);
+ cImage *GetLogo(string channelID, int width, int height);
+ bool LogoExists(string channelID);
+ cImage *GetSeparatorLogo(string name, int width, int height);
+ bool SeparatorLogoExists(string name);
+ //icons
+ void CacheIcon(eImageType type, string path, int width, int height);
+ cImage *GetIcon(eImageType type, string name, int width, int height);
+ string GetIconName(string label);
+ //skinparts
+ void CacheSkinpart(string path, int width, int height);
+ cImage *GetSkinpart(string name, int width, int height);
+ //helpers
+ void Clear(void);
+ void Debug(bool full);
+ void GetIconCacheSize(int &num, int &size);
+ void GetLogoCacheSize(int &num, int &size);
+ void GetSkinpartsCacheSize(int &num, int &size);
+private:
+ static cMutex mutex;
+ static string items[16];
+ cImage *tempStaticLogo;
+ map<string, cImage*> iconCache;
+ map<string, cImage*> channelLogoCache;
+ map<string, cImage*> skinPartsCache;
+ bool LoadIcon(eImageType type, string name);
+ bool LoadLogo(const cChannel *channel);
+ bool LoadSeparatorLogo(string name);
+ bool LoadSkinpart(string name);
+};
+
+#endif //__NOPACITY_IMAGECACHE_H
diff --git a/libcore/imageloader.c b/libcore/imageloader.c
new file mode 100644
index 0000000..1b220a6
--- /dev/null
+++ b/libcore/imageloader.c
@@ -0,0 +1,56 @@
+#include "../config.h"
+#include "helpers.h"
+#include "imageloader.h"
+#include <math.h>
+#include <string>
+#include <dirent.h>
+#include <iostream>
+
+using namespace Magick;
+
+cImageLoader::cImageLoader() : cImageMagickWrapper() {
+}
+
+cImageLoader::~cImageLoader() {
+}
+
+cImage cImageLoader::GetImage() {
+ return CreateImageCopy();
+}
+
+bool cImageLoader::LoadImage(const char *path, int width, int height) {
+ if (cImageMagickWrapper::LoadImage(path)) {
+ buffer.sample(Geometry(width, height));
+ return true;
+ }
+ return false;
+}
+
+void cImageLoader::DeterminateChannelLogoSize(int &width, int &height) {
+ cString logoPath = cString::sprintf("%s%s/logos/", *config.skinPath, Setup.OSDTheme);
+ cString logoExt = config.logoExtension;
+ DIR *folder = NULL;
+ struct dirent *file;
+ folder = opendir(logoPath);
+ if (!folder) {
+ return;
+ }
+ while (file = readdir(folder)) {
+ if (endswith(file->d_name, *logoExt)) {
+ std::stringstream filePath;
+ filePath << *logoPath << file->d_name;
+ Image logo;
+ try {
+ logo.read(filePath.str().c_str());
+ Geometry g = logo.size();
+ int logoWidth = g.width();
+ int logoHeight = g.height();
+ if (logoWidth > 0 && logoHeight > 0) {
+ width = logoWidth;
+ height = logoHeight;
+ return;
+ }
+ } catch( ... ) { }
+ }
+ }
+}
diff --git a/libcore/imageloader.h b/libcore/imageloader.h
new file mode 100644
index 0000000..2a148be
--- /dev/null
+++ b/libcore/imageloader.h
@@ -0,0 +1,23 @@
+#ifndef __NOPACITY_IMAGELOADER_H
+#define __NOPACITY_IMAGELOADER_H
+
+#define X_DISPLAY_MISSING
+
+#include <vdr/osd.h>
+#include <vdr/skins.h>
+#include <Magick++.h>
+#include "imagemagickwrapper.h"
+
+using namespace Magick;
+
+class cImageLoader : public cImageMagickWrapper {
+public:
+ cImageLoader();
+ ~cImageLoader();
+ cImage GetImage();
+ bool LoadImage(const char *path, int width, int height);
+ void DeterminateChannelLogoSize(int &width, int &height);
+private:
+};
+
+#endif //__NOPACITY_IMAGELOADER_H
diff --git a/libcore/imagemagickwrapper.c b/libcore/imagemagickwrapper.c
new file mode 100644
index 0000000..ab1bcba
--- /dev/null
+++ b/libcore/imagemagickwrapper.c
@@ -0,0 +1,162 @@
+#include <string>
+#include <sstream>
+#include "imagemagickwrapper.h"
+#include "../config.h"
+#include "imagescaler.h"
+
+cImageMagickWrapper::cImageMagickWrapper() {
+ InitializeMagick(NULL);
+}
+
+cImageMagickWrapper::~cImageMagickWrapper() {
+}
+
+cImage *cImageMagickWrapper::CreateImage(int width, int height, bool preserveAspect) {
+ int w, h;
+ w = buffer.columns();
+ h = buffer.rows();
+ if (width == 0)
+ width = w;
+ if (height == 0)
+ height = h;
+ if (preserveAspect) {
+ unsigned scale_w = 1000 * width / w;
+ unsigned scale_h = 1000 * height / h;
+ if (scale_w > scale_h)
+ width = w * height / h;
+ else
+ height = h * width / w;
+ }
+ const PixelPacket *pixels = buffer.getConstPixels(0, 0, w, h);
+ cImage *image = new cImage(cSize(width, height));
+ tColor *imgData = (tColor *)image->Data();
+ if (w != width || h != height) {
+ ImageScaler scaler;
+ scaler.SetImageParameters(imgData, width, width, height, w, h);
+ for (const void *pixels_end = &pixels[w*h]; pixels < pixels_end; ++pixels)
+ scaler.PutSourcePixel(pixels->blue / ((MaxRGB + 1) / 256),
+ pixels->green / ((MaxRGB + 1) / 256),
+ pixels->red / ((MaxRGB + 1) / 256),
+ ~((unsigned char)(pixels->opacity / ((MaxRGB + 1) / 256))));
+ return image;
+ }
+ for (const void *pixels_end = &pixels[width*height]; pixels < pixels_end; ++pixels)
+ *imgData++ = ((~int(pixels->opacity / ((MaxRGB + 1) / 256)) << 24) |
+ (int(pixels->green / ((MaxRGB + 1) / 256)) << 8) |
+ (int(pixels->red / ((MaxRGB + 1) / 256)) << 16) |
+ (int(pixels->blue / ((MaxRGB + 1) / 256)) ));
+ return image;
+}
+
+cImage cImageMagickWrapper::CreateImageCopy() {
+ int w, h;
+ w = buffer.columns();
+ h = buffer.rows();
+ cImage image (cSize(w, h));
+ const PixelPacket *pixels = buffer.getConstPixels(0, 0, w, h);
+ for (int iy = 0; iy < h; ++iy) {
+ for (int ix = 0; ix < w; ++ix) {
+ tColor col = (~int(pixels->opacity * 255 / MaxRGB) << 24)
+ | (int(pixels->green * 255 / MaxRGB) << 8)
+ | (int(pixels->red * 255 / MaxRGB) << 16)
+ | (int(pixels->blue * 255 / MaxRGB) );
+ image.SetPixel(cPoint(ix, iy), col);
+ ++pixels;
+ }
+ }
+ return image;
+}
+
+bool cImageMagickWrapper::LoadImage(std::string FileName, std::string Path, std::string Extension) {
+ try {
+ std::stringstream sstrImgFile;
+ sstrImgFile << Path << FileName << "." << Extension;
+ std::string imgFile = sstrImgFile.str();
+ if (config.debugImageLoading)
+ dsyslog("skindesigner: trying to load: %s", imgFile.c_str());
+ buffer.read(imgFile.c_str());
+ if (config.debugImageLoading)
+ dsyslog("skindesigner: %s sucessfully loaded", imgFile.c_str());
+ } catch( Magick::Warning &warning ) {
+ if (config.debugImageLoading)
+ dsyslog("skindesigner: Magick Warning: %s", warning.what());
+ return true;
+ } catch( Magick::Error &error ) {
+ if (config.debugImageLoading)
+ dsyslog("skindesigner: Magick Error: %s", error.what());
+ return false;
+ } catch(...) {
+ if (config.debugImageLoading)
+ dsyslog("skindesigner: an unknown Magick error occured during image loading");
+ return false;
+ }
+ return true;
+}
+
+bool cImageMagickWrapper::LoadImage(const char *fullpath) {
+ if ((fullpath == NULL) || (strlen(fullpath) < 5))
+ return false;
+ try {
+ if (config.debugImageLoading)
+ dsyslog("skindesigner: trying to load: %s", fullpath);
+ buffer.read(fullpath);
+ if (config.debugImageLoading)
+ dsyslog("skindesigner: %s sucessfully loaded", fullpath);
+ } catch( Magick::Warning &warning ) {
+ if (config.debugImageLoading)
+ dsyslog("skindesigner: Magick Warning: %s", warning.what());
+ return true;
+ } catch( Magick::Error &error ) {
+ if (config.debugImageLoading)
+ dsyslog("skindesigner: Magick Error: %s", error.what());
+ return false;
+ } catch(...) {
+ if (config.debugImageLoading)
+ dsyslog("skindesigner: an unknown Magick error occured during image loading");
+ return false;
+ }
+ return true;
+}
+
+Color cImageMagickWrapper::Argb2Color(tColor col) {
+ tIndex alpha = (col & 0xFF000000) >> 24;
+ tIndex red = (col & 0x00FF0000) >> 16;
+ tIndex green = (col & 0x0000FF00) >> 8;
+ tIndex blue = (col & 0x000000FF);
+ Color color(MaxRGB*red/255, MaxRGB*green/255, MaxRGB*blue/255, MaxRGB*(0xFF-alpha)/255);
+ return color;
+}
+
+void cImageMagickWrapper::CreateGradient(tColor back, tColor blend, int width, int height, double wfactor, double hfactor) {
+ Color Back = Argb2Color(back);
+ Color Blend = Argb2Color(blend);
+ int maxw = MaxRGB * wfactor;
+ int maxh = MaxRGB * hfactor;
+
+ Image imgblend(Geometry(width, height), Blend);
+ imgblend.modifyImage();
+ imgblend.type(TrueColorMatteType);
+ PixelPacket *pixels = imgblend.getPixels(0, 0, width, height);
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ PixelPacket *pixel = pixels + y * width + x;
+ int opacity = (maxw / width * x + maxh - maxh / height * y) / 2;
+ pixel->opacity = (opacity <= MaxRGB) ? opacity : MaxRGB;
+ }
+ }
+ imgblend.syncPixels();
+
+ Image imgback(Geometry(width, height), Back);
+ imgback.composite(imgblend, 0, 0, OverCompositeOp);
+
+ buffer = imgback;
+}
+
+void cImageMagickWrapper::CreateBackground(tColor back, tColor blend, int width, int height, bool mirror) {
+ CreateGradient(back, blend, width, height, 0.8, 0.8);
+ if (mirror)
+ buffer.flop();
+}
+void cImageMagickWrapper::CreateBackgroundReverse(tColor back, tColor blend, int width, int height) {
+ CreateGradient(back, blend, width, height, 1.3, 0.7);
+}
diff --git a/libcore/imagemagickwrapper.h b/libcore/imagemagickwrapper.h
new file mode 100644
index 0000000..5f9901e
--- /dev/null
+++ b/libcore/imagemagickwrapper.h
@@ -0,0 +1,28 @@
+#ifndef __NOPACITY_IMAGEMAGICKWRAPPER_H
+#define __NOPACITY_IMAGEMAGICKWRAPPER_H
+
+#define X_DISPLAY_MISSING
+
+#include <Magick++.h>
+#include <vdr/osd.h>
+
+using namespace Magick;
+
+class cImageMagickWrapper {
+private:
+ void CreateGradient(tColor back, tColor blend, int width, int height, double wfactor, double hfactor);
+public:
+ cImageMagickWrapper();
+ ~cImageMagickWrapper();
+protected:
+ Image buffer;
+ Color Argb2Color(tColor col);
+ cImage *CreateImage(int width, int height, bool preserveAspect = true);
+ cImage CreateImageCopy(void);
+ bool LoadImage(std::string FileName, std::string Path, std::string Extension);
+ bool LoadImage(const char *fullpath);
+ void CreateBackground(tColor back, tColor blend, int width, int height, bool mirror = false);
+ void CreateBackgroundReverse(tColor back, tColor blend, int width, int height);
+};
+
+#endif //__NOPACITY_IMAGEMAGICKWRAPPER_H
diff --git a/libcore/imagescaler.c b/libcore/imagescaler.c
new file mode 100644
index 0000000..64fe3dc
--- /dev/null
+++ b/libcore/imagescaler.c
@@ -0,0 +1,149 @@
+
+#include "imagescaler.h"
+
+#include <cstdlib>
+#include <cmath>
+
+ImageScaler::ImageScaler() :
+ m_memory(NULL),
+ m_hor_filters(NULL),
+ m_ver_filters(NULL),
+ m_buffer(NULL),
+ m_dst_image(NULL),
+ m_dst_stride(0),
+ m_dst_width(0),
+ m_dst_height(0),
+ m_src_width(0),
+ m_src_height(0),
+ m_src_x(0),
+ m_src_y(0),
+ m_dst_x(0),
+ m_dst_y(0) {
+}
+
+ImageScaler::~ImageScaler() {
+ if ( m_memory ) free( m_memory );
+}
+
+// sin(x)/(x)
+static float sincf( float x ) {
+ if ( fabsf(x) < 0.05f ) return 1.0f - (1.0f/6.0f)*x*x; // taylor series approximation to avoid 0/0
+ return sin(x)/x;
+}
+
+static void CalculateFilters( ImageScaler::Filter *filters, int dst_size, int src_size ) {
+ const float fc = dst_size >= src_size ? 1.0f : ((float) dst_size)/((float) src_size);
+
+ for (int i = 0; i < dst_size; i++) {
+ const int d = 2*dst_size; // sample position denominator
+ const int e = (2*i+1) * src_size - dst_size; // sample position enumerator
+ int offset = e / d; // truncated sample position
+ const float sub_offset = ((float) (e - offset*d)) / ((float) d); // exact sample position is (float) e/d = offset + sub_offset
+
+ // calculate filter coefficients
+ float h[4];
+ for (int j=0; j<4; j++) {
+ const float t = 3.14159265359f * (sub_offset+(1-j));
+ h[j] = sincf( fc * t ) * cosf( 0.25f * t ); // sinc-lowpass and cos-window
+ }
+
+ // ensure that filter does not reach out off image bounds:
+ while ( offset < 1 ) {
+ h[0] += h[1];
+ h[1] = h[2];
+ h[2] = h[3];
+ h[3] = 0.0f;
+ offset++;
+ }
+
+ while ( offset+3 > src_size ) {
+ h[3] += h[2];
+ h[2] = h[1];
+ h[1] = h[0];
+ h[0] = 0.0f;
+ offset--;
+ }
+
+ // coefficients are normalized to sum up to 2048
+ const float norm = 2048.0f / ( h[0] + h[1] + h[2] + h[3] );
+
+ offset--; // offset of fist used pixel
+
+ filters[i].m_offset = offset + 4; // store offset of first unused pixel
+
+ for (int j=0; j<4; j++) {
+ const float t = norm * h[j];
+ filters[i].m_coeff[(offset+j) & 3] = (int) ((t > 0.0f) ? (t+0.5f) : (t-0.5f)); // consider ring buffer index permutations
+ }
+ }
+
+ // set end marker
+ filters[dst_size].m_offset = (unsigned) -1;
+
+}
+
+void ImageScaler::SetImageParameters( unsigned *dst_image, unsigned dst_stride, unsigned dst_width, unsigned dst_height, unsigned src_width, unsigned src_height ) {
+ m_src_x = 0;
+ m_src_y = 0;
+ m_dst_x = 0;
+ m_dst_y = 0;
+
+ m_dst_image = dst_image;
+ m_dst_stride = dst_stride;
+
+ // if image dimensions do not change we can keep the old filter coefficients
+ if ( (src_width == m_src_width) && (src_height == m_src_height) && (dst_width == m_dst_width) && (dst_height == m_dst_height) ) return;
+
+ m_dst_width = dst_width;
+ m_dst_height = dst_height;
+ m_src_width = src_width;
+ m_src_height = src_height;
+
+ if ( m_memory ) free( m_memory );
+
+ const unsigned hor_filters_size = (m_dst_width + 1) * sizeof(Filter); // reserve one extra position for end marker
+ const unsigned ver_filters_size = (m_dst_height + 1) * sizeof(Filter);
+ const unsigned buffer_size = 4 * m_dst_width * sizeof(TmpPixel);
+
+ char *p = (char *) malloc( hor_filters_size + ver_filters_size + buffer_size );
+
+ m_memory = p;
+
+ m_hor_filters = (Filter *) p; p += hor_filters_size;
+ m_ver_filters = (Filter *) p; p += ver_filters_size;
+ m_buffer = (TmpPixel *) p;
+
+ CalculateFilters( m_hor_filters, m_dst_width , m_src_width );
+ CalculateFilters( m_ver_filters, m_dst_height, m_src_height );
+}
+
+// shift range to 0..255 and clamp overflows
+static unsigned shift_clamp( int x ) {
+ x = ( x + (1<<21) ) >> 22;
+ if ( x < 0 ) return 0;
+ if ( x > 255 ) return 255;
+ return x;
+}
+
+void ImageScaler::NextSourceLine() {
+ m_dst_x = 0;
+ m_src_x = 0;
+ m_src_y++;
+
+ while ( m_ver_filters[m_dst_y].m_offset == m_src_y ) {
+ const int h0 = m_ver_filters[m_dst_y].m_coeff[0];
+ const int h1 = m_ver_filters[m_dst_y].m_coeff[1];
+ const int h2 = m_ver_filters[m_dst_y].m_coeff[2];
+ const int h3 = m_ver_filters[m_dst_y].m_coeff[3];
+ const TmpPixel *src = m_buffer;
+ unsigned *dst = m_dst_image + m_dst_stride * m_dst_y;
+
+ for (unsigned i=0; i<m_dst_width; i++) {
+ const ImageScaler::TmpPixel t( src[0]*h0 + src[1]*h1 + src[2]*h2 + src[3]*h3 );
+ src += 4;
+ dst[i] = shift_clamp(t[0]) | (shift_clamp(t[1])<<8) | (shift_clamp(t[2])<<16) | (shift_clamp(t[3])<<24);
+ }
+
+ m_dst_y++;
+ }
+}
diff --git a/libcore/imagescaler.h b/libcore/imagescaler.h
new file mode 100644
index 0000000..1182811
--- /dev/null
+++ b/libcore/imagescaler.h
@@ -0,0 +1,97 @@
+#ifndef _ImageScaler_h
+#define _ImageScaler_h
+
+/*!
+ * this class scales images consisting of 4 components (RGBA)
+ * to an arbitrary size using a 4-tap filter
+ */
+class ImageScaler {
+public:
+
+ struct Filter {
+ unsigned m_offset;
+ short m_coeff[4];
+ };
+
+ ImageScaler();
+ ~ImageScaler();
+
+ //! set destination image and source image size
+ void SetImageParameters( unsigned *dst_image, unsigned dst_stride, unsigned dst_width, unsigned dst_height, unsigned src_width, unsigned src_height );
+
+ /*! process one pixel of source image; destination image is written while input is processed
+ * SetImageParameters() must be called first
+ */
+ void PutSourcePixel( unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3 ) {
+ m_hbuf[ (m_src_x++) & 3 ].Set( c0, c1, c2, c3 );
+
+ TmpPixel *bp = m_buffer + 4 * m_dst_x + (m_src_y & 3);
+ const Filter *fh;
+
+ while ( (fh=m_hor_filters+m_dst_x)->m_offset == m_src_x ) {
+ *bp = m_hbuf[0]*fh->m_coeff[0] + m_hbuf[1]*fh->m_coeff[1] + m_hbuf[2]*fh->m_coeff[2] + m_hbuf[3]*fh->m_coeff[3];
+ m_dst_x++;
+ bp += 4;
+ }
+
+ if ( m_src_x == m_src_width ) NextSourceLine();
+ }
+
+private:
+
+ //! temporary image pixel class - a 4-element integer vector
+ class TmpPixel {
+ public:
+ TmpPixel() {
+ }
+
+ TmpPixel( int c0, int c1, int c2, int c3 ) {
+ Set(c0,c1,c2,c3);
+ }
+
+ void Set( int c0, int c1, int c2, int c3 ) {
+ m_comp[0] = c0;
+ m_comp[1] = c1;
+ m_comp[2] = c2;
+ m_comp[3] = c3;
+ }
+
+ TmpPixel operator*( int s ) const {
+ return TmpPixel( m_comp[0]*s, m_comp[1]*s, m_comp[2]*s, m_comp[3]*s );
+ }
+
+ TmpPixel operator+( const TmpPixel &x ) const {
+ return TmpPixel( m_comp[0] + x[0], m_comp[1] + x[1], m_comp[2] + x[2], m_comp[3] + x[3] );
+ }
+
+ // return component i=[0..3] - No range check!
+ int operator[](unsigned i) const {
+ return m_comp[i];
+ }
+
+ private:
+ int m_comp[4];
+ };
+
+ //! this is called whenever one input line is processed completely
+ void NextSourceLine();
+
+ TmpPixel m_hbuf[4]; //! ring buffer for 4 input pixels
+ char *m_memory; //! buffer container
+ Filter *m_hor_filters; //! buffer for horizontal filters (one for each output image column)
+ Filter *m_ver_filters; //! buffer for vertical filters (one for each output image row)
+ TmpPixel *m_buffer; //! buffer contains 4 horizontally filtered input lines, multiplexed
+ unsigned *m_dst_image; //! pointer to destination image
+ unsigned m_dst_stride; //! destination image stride
+ unsigned m_dst_width; //! destination image width
+ unsigned m_dst_height; //! destination image height
+ unsigned m_src_width; //! source image width
+ unsigned m_src_height; //! source image height
+ unsigned m_src_x; //! x position of next source image pixel
+ unsigned m_src_y; //! y position of source image line currently beeing processed
+ unsigned m_dst_x; //! x position of next destination image pixel
+ unsigned m_dst_y; //! x position of next destination image line
+};
+
+#endif // _ImageScaler_h
+
diff --git a/libcore/pixmapcontainer.c b/libcore/pixmapcontainer.c
new file mode 100644
index 0000000..6329638
--- /dev/null
+++ b/libcore/pixmapcontainer.c
@@ -0,0 +1,477 @@
+#define __STL_CONFIG_H
+#include "pixmapcontainer.h"
+#include "../config.h"
+
+cMutex cPixmapContainer::mutex;
+cOsd *cPixmapContainer::osd = NULL;
+eFlushState cPixmapContainer::flushState = fsOpen;
+
+cPixmapContainer::cPixmapContainer(int numPixmaps) {
+ this->numPixmaps = numPixmaps;
+ pixContainerInit = true;
+ mutex.Lock();
+ pixmaps = new cPixmap*[numPixmaps];
+ pixmapsTransparency = new int[numPixmaps];
+ for(int i=0; i < numPixmaps; i++) {
+ pixmaps[i] = NULL;
+ pixmapsTransparency[i] = 0;
+ }
+ mutex.Unlock();
+ checkRunning = false;
+ fadeTime = 0;
+ deleteOsdOnExit = false;
+}
+
+cPixmapContainer::~cPixmapContainer(void) {
+ for (int i=0; i < numPixmaps; i++) {
+ mutex.Lock();
+ if (pixmaps[i] && osd) {
+ osd->DestroyPixmap(pixmaps[i]);
+ pixmaps[i] = NULL;
+ }
+ mutex.Unlock();
+ }
+ delete[] pixmaps;
+ delete[] pixmapsTransparency;
+ if (deleteOsdOnExit && osd) {
+ mutex.Lock();
+ delete osd;
+ osd = NULL;
+ mutex.Unlock();
+ }
+}
+
+bool cPixmapContainer::CreateOsd(int Left, int Top, int Width, int Height) {
+ if (osd) {
+ return true;
+ }
+ cOsd *newOsd = cOsdProvider::NewOsd(Left, Top);
+ if (newOsd) {
+ tArea Area = { 0, 0, Width, Height, 32 };
+ if (newOsd->SetAreas(&Area, 1) == oeOk) {
+ osd = newOsd;
+ return true;
+ }
+ }
+ return false;
+}
+
+void cPixmapContainer::LockFlush(void) {
+ flushState = fsLock;
+}
+
+void cPixmapContainer::OpenFlush(void) {
+ flushState = fsOpen;
+}
+
+bool cPixmapContainer::PixmapExists(int num) {
+ cMutexLock MutexLock(&mutex);
+ if (pixmaps[num])
+ return true;
+ return false;
+}
+
+void cPixmapContainer::DoFlush(void) {
+ cMutexLock MutexLock(&mutex);
+ if (!osd || (checkRunning && !Running()))
+ return;
+ if (flushState == fsOpen) {
+ osd->Flush();
+ }
+}
+
+void cPixmapContainer::CreatePixmap(int num, int Layer, const cRect &ViewPort, const cRect &DrawPort) {
+ cMutexLock MutexLock(&mutex);
+ if (!osd || (checkRunning && !Running()))
+ return;
+ pixmaps[num] = osd->CreatePixmap(Layer, ViewPort, DrawPort);
+ pixmaps[num]->Fill(clrTransparent);
+ if (pixContainerInit && fadeTime) {
+ pixmaps[num]->SetAlpha(0);
+ } else if (pixmapsTransparency[num] > 0) {
+ int alpha = (100 - pixmapsTransparency[num])*255/100;
+ pixmaps[num]->SetAlpha(alpha);
+ }
+}
+
+bool cPixmapContainer::DestroyPixmap(int num) {
+ cMutexLock MutexLock(&mutex);
+ if (pixmaps[num] && osd) {
+ osd->DestroyPixmap(pixmaps[num]);
+ pixmaps[num] = NULL;
+ return true;
+ }
+ return false;
+}
+
+void cPixmapContainer::DrawText(int num, const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, std::string fontName, int fontSize) {
+ if (checkRunning && !Running())
+ return;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return;
+ fontManager->Lock();
+ cFont *font = fontManager->Font(fontName, fontSize);
+ if (font)
+ pixmaps[num]->DrawText(Point, s, ColorFg, ColorBg, font);
+ fontManager->Unlock();
+}
+
+
+void cPixmapContainer::DrawRectangle(int num, const cRect &Rect, tColor Color) {
+ if (checkRunning && !Running())
+ return;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return;
+ pixmaps[num]->DrawRectangle(Rect, Color);
+}
+
+void cPixmapContainer::DrawEllipse(int num, const cRect &Rect, tColor Color, int Quadrants) {
+ if (checkRunning && !Running())
+ return;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return;
+ pixmaps[num]->DrawEllipse(Rect, Color, Quadrants);
+}
+
+void cPixmapContainer::DrawImage(int num, const cPoint &Point, const cImage &Image) {
+ if (checkRunning && !Running())
+ return;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return;
+ pixmaps[num]->DrawImage(Point, Image);
+}
+
+void cPixmapContainer::DrawBitmap(int num, const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool Overlay) {
+ if (checkRunning && !Running())
+ return;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return;
+ pixmaps[num]->DrawBitmap(Point, Bitmap, ColorFg, ColorBg, Overlay);
+}
+
+void cPixmapContainer::Fill(int num, tColor Color) {
+ if (checkRunning && !Running())
+ return;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return;
+ pixmaps[num]->Fill(Color);
+}
+
+void cPixmapContainer::SetAlpha(int num, int Alpha) {
+ if (checkRunning && !Running())
+ return;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return;
+ pixmaps[num]->SetAlpha(Alpha);
+}
+
+void cPixmapContainer::SetTransparency(int num, int Transparency) {
+ if (Transparency < 0 && Transparency > 100)
+ return;
+ pixmapsTransparency[num] = Transparency;
+}
+
+void cPixmapContainer::SetLayer(int num, int Layer) {
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return;
+ pixmaps[num]->SetLayer(Layer);
+}
+
+int cPixmapContainer::Width(int num) {
+ if (checkRunning && !Running())
+ return 0;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return 0;
+ int width = pixmaps[num]->ViewPort().Width();
+ return width;
+}
+
+int cPixmapContainer::Height(int num) {
+ if (checkRunning && !Running())
+ return 0;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return 0;
+ int height = pixmaps[num]->ViewPort().Height();
+ return height;
+}
+
+int cPixmapContainer::DrawportWidth(int num) {
+ if (checkRunning && !Running())
+ return 0;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return 0;
+ int width = pixmaps[num]->DrawPort().Width();
+ return width;
+}
+
+int cPixmapContainer::DrawportHeight(int num) {
+ if (checkRunning && !Running())
+ return 0;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return 0;
+ int height = pixmaps[num]->DrawPort().Height();
+ return height;
+}
+
+int cPixmapContainer::DrawportX(int num) {
+ if (checkRunning && !Running())
+ return 0;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return 0;
+ int x = pixmaps[num]->DrawPort().X();
+ return x;
+}
+
+int cPixmapContainer::DrawportY(int num) {
+ if (checkRunning && !Running())
+ return 0;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return 0;
+ int y = pixmaps[num]->DrawPort().Y();
+ return y;
+}
+
+void cPixmapContainer::SetDrawPortPoint(int num, const cPoint &Point) {
+ if (checkRunning && !Running())
+ return;
+ cMutexLock MutexLock(&mutex);
+ if (!pixmaps[num])
+ return;
+ pixmaps[num]->SetDrawPortPoint(Point);
+}
+
+/***************************************************************************
+* HELPERS -- do not access the pixmaps array directly, use wrapper functions
+* to ensure that a proper lock is set before accessing pixmaps
+****************************************************************************/
+
+void cPixmapContainer::FadeIn(void) {
+ if (!fadeTime)
+ return;
+ uint64_t Start = cTimeMs::Now();
+ int FadeFrameTime = fadeTime / 10;
+ while (Running()) {
+ uint64_t Now = cTimeMs::Now();
+ double t = min(double(Now - Start) / fadeTime, 1.0);
+ int Alpha = t * ALPHA_OPAQUE;
+ for (int i = 0; i < numPixmaps; i++) {
+ if (!PixmapExists(i))
+ continue;
+ if (pixmapsTransparency[i] > 0) {
+ int alpha = (100 - pixmapsTransparency[i])*Alpha/100;
+ SetAlpha(i, alpha);
+ } else {
+ SetAlpha(i, Alpha);
+ }
+ }
+ DoFlush();
+ int Delta = cTimeMs::Now() - Now;
+ if (Running() && (Delta < FadeFrameTime))
+ cCondWait::SleepMs(FadeFrameTime - Delta);
+ if ((int)(Now - Start) > fadeTime)
+ break;
+ }
+}
+
+void cPixmapContainer::FadeOut(void) {
+ if (!fadeTime)
+ return;
+ uint64_t Start = cTimeMs::Now();
+ int FadeFrameTime = fadeTime / 10;
+ while (true) {
+ uint64_t Now = cTimeMs::Now();
+ double t = min(double(Now - Start) / fadeTime, 1.0);
+ int Alpha = (1 - t) * ALPHA_OPAQUE;
+ for (int i = 0; i < numPixmaps; i++) {
+ if (!PixmapExists(i))
+ continue;
+ if (pixmapsTransparency[i] > 0) {
+ int alpha = (100 - pixmapsTransparency[i])*Alpha/100;
+ SetAlpha(i, alpha);
+ } else {
+ SetAlpha(i, Alpha);
+ }
+ }
+ DoFlush();
+ int Delta = cTimeMs::Now() - Now;
+ if (Running() && (Delta < FadeFrameTime))
+ cCondWait::SleepMs(FadeFrameTime - Delta);
+ if ((int)(Now - Start) > fadeTime)
+ break;
+ }
+}
+
+/*****************************************
+* scrollSpeed: 1 slow
+* 2 medium
+* 3 fast
+******************************************/
+void cPixmapContainer::ScrollHorizontal(int num, int scrollDelay, int scrollSpeed, int scrollMode) {
+ bool carriageReturn = (scrollMode == 1) ? true : false;
+
+ int scrollDelta = 1;
+ int drawPortX;
+
+ int FrameTime = 0;
+ if (scrollSpeed == 1)
+ FrameTime = 50;
+ else if (scrollSpeed == 2)
+ FrameTime = 30;
+ else
+ FrameTime = 15;
+ if (!Running())
+ return;
+ int maxX = DrawportWidth(num) - Width(num);
+ bool doSleep = false;
+ while (Running()) {
+ if (doSleep) {
+ DoSleep(scrollDelay);
+ doSleep = false;
+ }
+ if (!Running())
+ return;
+ uint64_t Now = cTimeMs::Now();
+ drawPortX = DrawportX(num);
+ drawPortX -= scrollDelta;
+
+ if (abs(drawPortX) > maxX) {
+ DoSleep(scrollDelay);
+ if (carriageReturn)
+ drawPortX = 0;
+ else {
+ scrollDelta *= -1;
+ drawPortX -= scrollDelta;
+ }
+ doSleep = true;
+ }
+ if (!carriageReturn && (drawPortX == 0)) {
+ scrollDelta *= -1;
+ doSleep = true;
+ }
+ SetDrawPortPoint(num, cPoint(drawPortX, 0));
+ int Delta = cTimeMs::Now() - Now;
+ DoFlush();
+ if (Running() && (Delta < FrameTime))
+ cCondWait::SleepMs(FrameTime - Delta);
+ }
+}
+
+/*****************************************
+* scrollSpeed: 1 slow
+* 2 medium
+* 3 fast
+******************************************/
+void cPixmapContainer::ScrollVertical(int num, int scrollDelay, int scrollSpeed) {
+ if (!scrollSpeed)
+ return;
+ DoSleep(scrollDelay);
+ int drawPortY;
+ int FrameTime = 0;
+ if (scrollSpeed == 1)
+ FrameTime = 50;
+ else if (scrollSpeed == 2)
+ FrameTime = 30;
+ else
+ FrameTime = 15;
+ int maxY = DrawportHeight(num) - Height(num);
+ bool doSleep = false;
+ while (Running()) {
+ if (doSleep) {
+ doSleep = false;
+ DoSleep(scrollDelay);
+ }
+ uint64_t Now = cTimeMs::Now();
+ drawPortY = DrawportY(num);
+ drawPortY -= 1;
+ if (abs(drawPortY) > maxY) {
+ doSleep = true;
+ DoSleep(scrollDelay);
+ drawPortY = 0;
+ }
+ SetDrawPortPoint(num, cPoint(0, drawPortY));
+ if (doSleep) {
+ DoSleep(scrollDelay);
+ }
+ int Delta = cTimeMs::Now() - Now;
+ DoFlush();
+ if (Running() && (Delta < FrameTime))
+ cCondWait::SleepMs(FrameTime - Delta);
+ }
+}
+
+void cPixmapContainer::CancelSave(void) {
+ Cancel(-1);
+ while (Active())
+ cCondWait::SleepMs(10);
+}
+
+void cPixmapContainer::DoSleep(int duration) {
+ int sleepSlice = 10;
+ for (int i = 0; Running() && (i*sleepSlice < duration); i++)
+ cCondWait::SleepMs(sleepSlice);
+}
+
+void cPixmapContainer::DrawBlendedBackground(int num, int xStart, int width, tColor color, tColor colorBlending, bool fromTop) {
+ int height = Height(num);
+ int numSteps = 16;
+ int alphaStep = 0x0F;
+ int alpha = 0x00;
+ int step, begin, end;
+ if (fromTop) {
+ step = 1;
+ begin = 0;
+ end = numSteps;
+ } else {
+ step = -1;
+ begin = height;
+ end = height - numSteps;
+ }
+ tColor clr;
+ bool cont = true;
+ for (int i = begin; cont; i = i + step) {
+ clr = AlphaBlend(color, colorBlending, alpha);
+ DrawRectangle(num, cRect(xStart,i,width,1), clr);
+ alpha += alphaStep;
+ if (i == end)
+ cont = false;
+ }
+}
+
+void cPixmapContainer::DrawRoundedCorners(int num, int radius, int x, int y, int width, int height) {
+ if (radius > 2) {
+ DrawEllipse(num, cRect(x, y, radius, radius), clrTransparent, -2);
+ DrawEllipse(num, cRect(x + width - radius, y , radius, radius), clrTransparent, -1);
+ DrawEllipse(num, cRect(x, y + height - radius, radius, radius), clrTransparent, -3);
+ DrawEllipse(num, cRect(x + width - radius, y + height - radius, radius, radius), clrTransparent, -4);
+ }
+}
+
+void cPixmapContainer::DrawRoundedCornersWithBorder(int num, tColor borderColor, int radius, int width, int height) {
+ if (radius < 3)
+ return;
+ DrawEllipse(num, cRect(0,0,radius,radius), borderColor, -2);
+ DrawEllipse(num, cRect(-1,-1,radius,radius), clrTransparent, -2);
+
+ DrawEllipse(num, cRect(width-radius,0,radius,radius), borderColor, -1);
+ DrawEllipse(num, cRect(width-radius+1,-1,radius,radius), clrTransparent, -1);
+
+ DrawEllipse(num, cRect(0,height-radius,radius,radius), borderColor, -3);
+ DrawEllipse(num, cRect(-1,height-radius+1,radius,radius), clrTransparent, -3);
+
+ DrawEllipse(num, cRect(width-radius,height-radius,radius,radius), borderColor, -4);
+ DrawEllipse(num, cRect(width-radius+1,height-radius+1,radius,radius), clrTransparent, -4);
+}
diff --git a/libcore/pixmapcontainer.h b/libcore/pixmapcontainer.h
new file mode 100644
index 0000000..06f9104
--- /dev/null
+++ b/libcore/pixmapcontainer.h
@@ -0,0 +1,73 @@
+#ifndef __PIXMAP_CONTAINER_H
+#define __PIXMAP_CONTAINER_H
+
+#include <string>
+#include <vdr/plugin.h>
+#include "fontmanager.h"
+
+enum eFlushState {
+ fsOpen,
+ fsLock,
+ fsCount,
+};
+
+class cPixmapContainer : public cThread {
+private:
+ static cMutex mutex;
+ static cOsd *osd;
+ static eFlushState flushState;
+ bool pixContainerInit;
+ int numPixmaps;
+ cPixmap **pixmaps;
+ int *pixmapsTransparency;
+ bool checkRunning;
+ int fadeTime;
+ bool deleteOsdOnExit;
+protected:
+ void SetInitFinished(void) { pixContainerInit = false; };
+ bool CreateOsd(int Left, int Top, int Width, int Height);
+ void DeleteOsdOnExit(void) { deleteOsdOnExit = true; };
+ void LockFlush(void);
+ void OpenFlush(void);
+ //Wrappers for access to pixmaps
+ bool PixmapExists(int num);
+ int NumPixmaps(void) { return numPixmaps; };
+ void CreatePixmap(int num, int Layer, const cRect &ViewPort, const cRect &DrawPort = cRect::Null);
+ bool DestroyPixmap(int num);
+ void DrawText(int num, const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, std::string fontName, int fontSize);
+ void DrawRectangle(int num, const cRect &Rect, tColor Color);
+ void DrawEllipse(int num, const cRect &Rect, tColor Color, int Quadrants = 0);
+ void DrawImage(int num, const cPoint &Point, const cImage &Image);
+ void DrawBitmap(int num, const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg = 0, tColor ColorBg = 0, bool Overlay = false);
+ void Fill(int num, tColor Color);
+ void SetAlpha(int num, int Alpha);
+ void SetTransparency(int num, int Transparency);
+ void SetLayer(int num, int Layer);
+ int Width(int num);
+ int Height(int num);
+ int DrawportWidth(int num);
+ int DrawportHeight(int num);
+ int DrawportX(int num);
+ int DrawportY(int num);
+ void SetDrawPortPoint(int num, const cPoint &Point);
+ void SetCheckRunning(void) { checkRunning = true; };
+ void UnsetCheckRunning(void) { checkRunning = false; };
+ //HELPERS -- do not access the pixmaps array directly, use wrapper functions
+ void SetFadeTime(int fade) { fadeTime = fade; };
+ void FadeIn(void);
+ void FadeOut(void);
+ void ScrollVertical(int num, int scrollDelay, int scrollSpeed);
+ void ScrollHorizontal(int num, int scrollDelay, int scrollSpeed, int scrollMode);
+ void CancelSave(void);
+ void DoSleep(int duration);
+ void DrawBlendedBackground(int num, int xStart, int width, tColor color, tColor colorBlending, bool fromTop);
+ void DrawRoundedCorners(int num, int radius, int x, int y, int width, int height);
+ void DrawRoundedCornersWithBorder(int num, tColor borderColor, int radius, int width, int height);
+public:
+ cPixmapContainer(int numPixmaps);
+ virtual ~cPixmapContainer(void);
+ void DoFlush(void);
+ virtual void Action(void) {};
+};
+
+#endif //__PIXMAP_CONTAINER_H \ No newline at end of file
diff --git a/libcore/timers.c b/libcore/timers.c
new file mode 100644
index 0000000..09af69b
--- /dev/null
+++ b/libcore/timers.c
@@ -0,0 +1,84 @@
+#include "timers.h"
+#include "../services/epgsearch.h"
+#include "../services/remotetimers.h"
+
+static int CompareTimers(const void *a, const void *b) {
+ return (*(const cTimer **)a)->Compare(**(const cTimer **)b);
+}
+
+cGlobalSortedTimers::cGlobalSortedTimers(bool forceRefresh) : cVector<const cTimer *>(Timers.Count()) {
+ static bool initial = true;
+ static cRemoteTimerRefresh *remoteTimerRefresh = NULL;
+
+ if (forceRefresh)
+ initial = true;
+ //check if remotetimers plugin is available
+ static cPlugin* pRemoteTimers = cPluginManager::GetPlugin("remotetimers");
+
+ cSchedulesLock SchedulesLock;
+ const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
+
+ if (pRemoteTimers && initial) {
+ cString errorMsg;
+ pRemoteTimers->Service("RemoteTimers::RefreshTimers-v1.0", &errorMsg);
+ initial = false;
+ }
+
+ for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer))
+ Append(Timer);
+
+ //if remotetimers plugin is available, take timers also from him
+ if (pRemoteTimers) {
+ cTimer* remoteTimer = NULL;
+ while (pRemoteTimers->Service("RemoteTimers::ForEach-v1.0", &remoteTimer) && remoteTimer != NULL) {
+ remoteTimer->SetEventFromSchedule(Schedules); // make sure the event is current
+ Append(remoteTimer);
+ }
+ }
+
+ Sort(CompareTimers);
+
+ if (pRemoteTimers && (remoteTimerRefresh == NULL))
+ remoteTimerRefresh = new cRemoteTimerRefresh();
+}
+
+int cGlobalSortedTimers::NumTimerConfilicts(void) {
+ int numConflicts = 0;
+ cPlugin *p = cPluginManager::GetPlugin("epgsearch");
+ if (p) {
+ Epgsearch_lastconflictinfo_v1_0 *serviceData = new Epgsearch_lastconflictinfo_v1_0;
+ if (serviceData) {
+ serviceData->nextConflict = 0;
+ serviceData->relevantConflicts = 0;
+ serviceData->totalConflicts = 0;
+ p->Service("Epgsearch-lastconflictinfo-v1.0", serviceData);
+ if (serviceData->relevantConflicts > 0) {
+ numConflicts = serviceData->relevantConflicts;
+ }
+ delete serviceData;
+ }
+ }
+ return numConflicts;
+}
+
+cRemoteTimerRefresh::cRemoteTimerRefresh(): cThread("skindesigner: RemoteTimers::RefreshTimers") {
+ Start();
+}
+
+cRemoteTimerRefresh::~cRemoteTimerRefresh(void) {
+ Cancel(-1);
+ while (Active())
+ cCondWait::SleepMs(10);
+}
+
+void cRemoteTimerRefresh::Action(void) {
+ #define REFESH_INTERVALL_MS 30000
+ while (Running()) {
+ cCondWait::SleepMs(REFESH_INTERVALL_MS);
+ if (!cOsd::IsOpen()) {//make sure that no timer is currently being edited
+ cGlobalSortedTimers(true);
+ Timers.SetModified();
+ }
+ }
+}
+ \ No newline at end of file
diff --git a/libcore/timers.h b/libcore/timers.h
new file mode 100644
index 0000000..81d988a
--- /dev/null
+++ b/libcore/timers.h
@@ -0,0 +1,20 @@
+#ifndef __NOPACITY_TIMERS_H
+#define __NOPACITY_TIMERS_H
+
+#include <vdr/timers.h>
+#include <vdr/plugin.h>
+
+class cGlobalSortedTimers : public cVector<const cTimer *> {
+ public:
+ cGlobalSortedTimers(bool forceRefresh = false);
+ int NumTimerConfilicts(void);
+};
+
+class cRemoteTimerRefresh: public cThread {
+ protected:
+ virtual void Action(void);
+ public:
+ cRemoteTimerRefresh(void);
+ virtual ~cRemoteTimerRefresh(void);
+};
+#endif //__NOPACITY_TIMERS_H
diff --git a/libtemplate/globals.c b/libtemplate/globals.c
new file mode 100644
index 0000000..9e9ce5f
--- /dev/null
+++ b/libtemplate/globals.c
@@ -0,0 +1,98 @@
+#include "globals.h"
+#include "xmlparser.h"
+#include <locale.h>
+
+cGlobals::cGlobals(void) {
+ fonts.insert(pair<string, string>("vdrOsd", Setup.FontOsd));
+ fonts.insert(pair<string, string>("vdrFix", Setup.FontFix));
+ fonts.insert(pair<string, string>("vdrSml", Setup.FontSml));
+
+ string loc = setlocale(LC_NAME, NULL);
+ size_t index = loc.find_first_of(".");
+ string langISO = "";
+ if (index > 0) {
+ langISO = loc.substr(0, index);
+ }
+ if (langISO.size() == 5) {
+ language = langISO.c_str();
+ } else {
+ language = "en_EN";
+ }
+ dsyslog("skindesigner: using language %s", language.c_str());
+}
+
+bool cGlobals::ReadFromXML(void) {
+ std::string xmlFile = "globals.xml";
+ cXmlParser parser;
+ if (!parser.ReadGlobals(this, xmlFile))
+ return false;
+ if (!parser.ParseGlobals())
+ return false;
+ return true;
+}
+
+bool cGlobals::Translate(string text, string &translation) {
+ string transStart = "{tr(";
+ string transEnd = ")}";
+ size_t foundStart = text.find(transStart);
+ size_t foundEnd = text.find(transEnd);
+ bool translated = false;
+
+ while (foundStart != string::npos && foundEnd != string::npos) {
+ string token = text.substr(foundStart + 1, foundEnd - foundStart);
+ string transToken = DoTranslate(token);
+ if (transToken.size() > 0)
+ translated = true;
+ else
+ return false;
+ text.replace(foundStart, foundEnd - foundStart + 2, transToken);
+ foundStart = text.find(transStart);
+ foundEnd = text.find(transEnd);
+ }
+ if (translated)
+ translation = text;
+ return translated;
+}
+
+string cGlobals::DoTranslate(string token) {
+ string translation = "";
+ map <string, map< string, string > >::iterator hit = translations.find(token);
+ if (hit == translations.end()) {
+ esyslog("skindesigner: invalid translation token %s", token.c_str());
+ return translation;
+ }
+ map< string, string > translats = hit->second;
+ map< string, string >::iterator trans = translats.find(language);
+ if (trans != translats.end()) {
+ translation = trans->second;
+ } else {
+ map< string, string >::iterator transDefault = translats.find("en_EN");
+ if (transDefault != translats.end()) {
+ translation = transDefault->second;
+ }
+ }
+ return translation;
+}
+
+void cGlobals::Debug(void) {
+ dsyslog("skindesigner: GLOBAL VARIABLES");
+ for (map <string, tColor>::iterator col = colors.begin(); col != colors.end(); col++) {
+ dsyslog("skindesigner: Color \"%s\": %x", (col->first).c_str(), col->second);
+ }
+ for (map <string, int>::iterator myInt = intVars.begin(); myInt != intVars.end(); myInt++) {
+ dsyslog("skindesigner: Integer Variable \"%s\": %d", (myInt->first).c_str(), myInt->second);
+ }
+ for (map <string, string>::iterator myStr = stringVars.begin(); myStr != stringVars.end(); myStr++) {
+ dsyslog("skindesigner: String Variable \"%s\": \"%s\"", (myStr->first).c_str(), (myStr->second).c_str());
+ }
+ for (map <string, string>::iterator font = fonts.begin(); font != fonts.end(); font++) {
+ dsyslog("skindesigner: Font \"%s\": \"%s\"", (font->first).c_str(), (font->second).c_str());
+ }
+ for (map <string, map< string, string > >::iterator trans = translations.begin(); trans != translations.end(); trans++) {
+ dsyslog("skindesigner: Translation Token %s", (trans->first).c_str());
+ map< string, string > tokenTrans = trans->second;
+ for (map< string, string >::iterator transTok = tokenTrans.begin(); transTok != tokenTrans.end(); transTok++) {
+ dsyslog("skindesigner: language %s, translation %s", (transTok->first).c_str(), (transTok->second).c_str());
+ }
+ }
+}
diff --git a/libtemplate/globals.h b/libtemplate/globals.h
new file mode 100644
index 0000000..f7a959e
--- /dev/null
+++ b/libtemplate/globals.h
@@ -0,0 +1,38 @@
+#ifndef __XMLGLOBALS_H
+#define __XMLGLOBALS_H
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <sstream>
+#include <vdr/plugin.h>
+
+using namespace std;
+
+typedef uint32_t tColor;
+
+// --- cGlobals -------------------------------------------------------------
+
+class cGlobals {
+private:
+ string language;
+ string DoTranslate(string token);
+public:
+ cGlobals(void);
+ virtual ~cGlobals(void) {};
+ map <string, tColor> colors;
+ map <string, int> intVars;
+ map <string, string> stringVars;
+ map <string, string> fonts;
+ map <string, map< string, string > > translations;
+ bool ReadFromXML(void);
+ bool Translate(string text, string &translation);
+ void Debug(void);
+};
+
+#endif //__XMLGLOBALS_H \ No newline at end of file
diff --git a/libtemplate/parameter.c b/libtemplate/parameter.c
new file mode 100644
index 0000000..e7dd30a
--- /dev/null
+++ b/libtemplate/parameter.c
@@ -0,0 +1,394 @@
+#include "parameter.h"
+
+using namespace std;
+
+// --- cNumericParameter -------------------------------------------------------------
+
+cNumericParameter::cNumericParameter(string value) {
+ this->value = value;
+ globals = NULL;
+ isValid = false;
+ width = 0;
+ height = 0;
+ columnWidth = -1;
+ rowHeight = -1;
+ hor = true;
+ defaultValue = 0;
+}
+
+cNumericParameter::~cNumericParameter(void) {
+}
+
+void cNumericParameter::SetAreaSize(int w, int h) {
+ width = w;
+ height = h;
+}
+
+int cNumericParameter::Parse(string &parsedValue) {
+ int retVal = defaultValue;
+
+ if (IsNumber(value)) {
+ isValid = true;
+ retVal = atoi(value.c_str());
+ return retVal;
+ }
+
+ //checking for percent value
+ bool isPercentValue = CheckPercentValue(retVal);
+ if (isPercentValue) {
+ isValid = true;
+ return retVal;
+ }
+
+ //checking for expression
+ bool isValidExpression = CheckExpression(retVal, parsedValue);
+ if (isValidExpression) {
+ isValid = true;
+ return retVal;
+ }
+
+ return retVal;
+}
+
+bool cNumericParameter::IsNumber(const string& s) {
+ string::const_iterator it = s.begin();
+ while (it != s.end() && isdigit(*it)) ++it;
+ return !s.empty() && it == s.end();
+}
+
+bool cNumericParameter::CheckPercentValue(int &val) {
+ bool ok = false;
+ size_t posPercent = value.find('%');
+ if (posPercent != string::npos) {
+ string strPerc = value.substr(0, posPercent);
+ if (!IsNumber(strPerc)) {
+ return ok;
+ }
+ int perc = atoi(strPerc.c_str());
+ if (hor) {
+ val = width * perc / 100;
+ } else {
+ val = height * perc / 100;
+ }
+ ok = true;
+ }
+ return ok;
+}
+
+bool cNumericParameter::CheckExpression(int &val, string &parsedVal) {
+ bool ok = false;
+ string parsedValue = value;
+ //remove white spaces
+ parsedValue.erase( std::remove_if( parsedValue.begin(), parsedValue.end(), ::isspace ), parsedValue.end() );
+
+ //check and replace {areawidth} and {areaheight} tokens
+ string tokenWidth = "{areawidth}";
+ string tokenHeight = "{areaheight}";
+
+ stringstream sw;
+ sw << width;
+ string strWidth = sw.str();
+ stringstream sh;
+ sh << height;
+ string strHeight = sh.str();
+
+ bool foundToken = true;
+ while(foundToken) {
+ size_t foundTokenWidth = parsedValue.find(tokenWidth);
+ if (foundTokenWidth != string::npos) {
+ parsedValue = parsedValue.replace(foundTokenWidth, tokenWidth.size(), strWidth);
+ } else {
+ foundToken = false;
+ }
+ }
+
+ foundToken = true;
+ while(foundToken) {
+ size_t foundTokenHeight = parsedValue.find(tokenHeight);
+ if (foundTokenHeight != string::npos) {
+ parsedValue = parsedValue.replace(foundTokenHeight, tokenHeight.size(), strHeight);
+ } else {
+ foundToken = false;
+ }
+ }
+
+ //check and replace {columnwidth} and {rowheight} tokens for loop functions
+ if (columnWidth > 0 || rowHeight > 0) {
+ tokenWidth = "{columnwidth}";
+ tokenHeight = "{rowheight}";
+ stringstream cw;
+ cw << columnWidth;
+ strWidth = cw.str();
+ stringstream rh;
+ rh << rowHeight;
+ strHeight = rh.str();
+
+ foundToken = true;
+ while(foundToken) {
+ size_t foundTokenWidth = parsedValue.find(tokenWidth);
+ if (foundTokenWidth != string::npos) {
+ parsedValue = parsedValue.replace(foundTokenWidth, tokenWidth.size(), strWidth);
+ } else {
+ foundToken = false;
+ }
+ }
+
+ foundToken = true;
+ while(foundToken) {
+ size_t foundTokenHeight = parsedValue.find(tokenHeight);
+ if (foundTokenHeight != string::npos) {
+ parsedValue = parsedValue.replace(foundTokenHeight, tokenHeight.size(), strHeight);
+ } else {
+ foundToken = false;
+ }
+ }
+ }
+
+ if (globals) {
+ for (map<string, int>::iterator globInt = globals->intVars.begin(); globInt != globals->intVars.end(); globInt++) {
+ stringstream sToken;
+ sToken << "{" << globInt->first << "}";
+ string token = sToken.str();
+ size_t foundToken = parsedValue.find(token);
+ if (foundToken != string::npos) {
+ stringstream st;
+ st << globInt->second;
+ parsedValue = parsedValue.replace(foundToken, token.size(), st.str());
+ }
+ }
+ }
+
+ if (IsNumber(parsedValue)) {
+ ok = true;
+ val = atoi(parsedValue.c_str());
+ return ok;
+ }
+
+ if (!ValidNumericExpression(parsedValue)) {
+ parsedVal = parsedValue;
+ return ok;
+ }
+ ok = true;
+ char * expression = new char[parsedValue.size() + 1];
+ std::copy(parsedValue.begin(), parsedValue.end(), expression);
+ expression[parsedValue.size()] = '\0';
+ int expRes = EvaluateTheExpression(expression);
+ val = expRes;
+ delete[] expression;
+ return ok;
+}
+
+bool cNumericParameter::ValidNumericExpression(string &parsedValue) {
+ string::const_iterator it = parsedValue.begin();
+ while (it != parsedValue.end() && (isdigit(*it) || *it == '.' || *it == ',' || *it == '+' || *it == '-' || *it == '*' || *it == '/')) ++it;
+ return !parsedValue.empty() && it == parsedValue.end();
+}
+
+int cNumericParameter::EvaluateTheExpression(char* expr) {
+ return round(ParseSummands(expr));
+}
+
+double cNumericParameter::ParseAtom(char*& expr) {
+ // Read the number from string
+ char* end_ptr;
+ double res = strtod(expr, &end_ptr);
+ // Advance the pointer and return the result
+ expr = end_ptr;
+ return res;
+}
+
+// Parse multiplication and division
+double cNumericParameter::ParseFactors(char*& expr) {
+ double num1 = ParseAtom(expr);
+ for(;;) {
+ // Save the operation
+ char op = *expr;
+ if(op != '/' && op != '*')
+ return num1;
+ expr++;
+ double num2 = ParseAtom(expr);
+ // Perform the saved operation
+ if(op == '/') {
+ if (num2 != 0) {
+ num1 /= num2;
+ }
+ } else
+ num1 *= num2;
+ }
+}
+
+// Parse addition and subtraction
+double cNumericParameter::ParseSummands(char*& expr) {
+ double num1 = ParseFactors(expr);
+ for(;;) {
+ char op = *expr;
+ if(op != '-' && op != '+')
+ return num1;
+ expr++;
+ double num2 = ParseFactors(expr);
+ if(op == '-')
+ num1 -= num2;
+ else
+ num1 += num2;
+ }
+}
+
+// --- cConditionalParameter -------------------------------------------------------------
+
+cConditionalParameter::cConditionalParameter(cGlobals *globals, string value) {
+ this->globals = globals;
+ isTrue = false;
+ this->value = value;
+ type = cpNone;
+}
+
+cConditionalParameter::~cConditionalParameter(void) {
+}
+
+void cConditionalParameter::Tokenize(void) {
+ size_t posAnd = value.find("++");
+ if (posAnd != string::npos) {
+ type = cpAnd;
+ TokenizeValue("++");
+ } else {
+ size_t posOr = value.find("||");
+ if (posOr != string::npos) {
+ type = cpOr;
+ TokenizeValue("||");
+ }
+ }
+ if (type == cpNone) {
+ InsertCondition(value);
+ }
+}
+
+bool cConditionalParameter::Evaluate(map < string, int > *intTokens, map < string, string > *stringTokens) {
+ isTrue = false;
+ bool first = true;
+ for (vector<sCondition>::iterator cond = conditions.begin(); cond != conditions.end(); cond++) {
+ bool tokenTrue = false;
+
+ if (cond->type == ctStringSet) {
+ if (stringTokens) {
+ map < string, string >::iterator hit = stringTokens->find(cond->tokenName);
+ if (hit != stringTokens->end()) {
+ string value = hit->second;
+ if (value.size() > 0)
+ tokenTrue = true;
+ }
+ }
+ } else {
+ int tokenValue = EvaluateParameter(cond->tokenName, intTokens, stringTokens);
+ if (cond->type == ctBool) {
+ tokenTrue = tokenValue;
+ } else if (cond->type == ctGreater) {
+ tokenTrue = (tokenValue > cond->compareValue) ? true : false;
+ } else if (cond->type == ctLower) {
+ tokenTrue = (tokenValue < cond->compareValue) ? true : false;
+ } else if (cond->type == ctEquals) {
+ tokenTrue = (tokenValue == cond->compareValue) ? true : false;
+ }
+ }
+
+ if (cond->isNegated)
+ tokenTrue = !tokenTrue;
+ if (type == cpAnd) {
+ if (first)
+ isTrue = tokenTrue;
+ else
+ isTrue = isTrue && tokenTrue;
+ } else if (type == cpOr) {
+ isTrue = isTrue || tokenTrue;
+ } else {
+ isTrue = tokenTrue;
+ }
+ first = false;
+ }
+}
+
+int cConditionalParameter::EvaluateParameter(string token, map < string, int > *intTokens, map < string, string > *stringTokens) {
+ //first check globals
+ map < string, int >::iterator hitGlobals = globals->intVars.find(token);
+ if (hitGlobals != globals->intVars.end()) {
+ return hitGlobals->second;
+ } else {
+ //then check tokens
+ if (intTokens) {
+ map < string, int >::iterator hit = intTokens->find(token);
+ if (hit != intTokens->end()) {
+ return hit->second;
+ }
+ }
+ if (stringTokens) {
+ map < string, string >::iterator hit = stringTokens->find(token);
+ if (hit != stringTokens->end()) {
+ string value = hit->second;
+ return atoi(value.c_str());
+ }
+ }
+ }
+ return 0;
+}
+
+void cConditionalParameter::TokenizeValue(string sep) {
+ string buffer = value;
+ bool sepFound = true;
+ while (sepFound) {
+ size_t posSep = buffer.find(sep);
+ if (posSep == string::npos) {
+ InsertCondition(buffer);
+ sepFound = false;
+ }
+ string token = buffer.substr(0, posSep);
+ buffer = buffer.replace(0, posSep + sep.size(), "");
+ InsertCondition(token);
+ }
+}
+
+void cConditionalParameter::InsertCondition(string cond) {
+ cond.erase( std::remove_if( cond.begin(), cond.end(), ::isspace ), cond.end() );
+
+ if (cond.size() < 1)
+ return;
+
+ size_t tokenStart = cond.find('{');
+ size_t tokenEnd = cond.find('}');
+
+ if (tokenStart == string::npos || tokenEnd == string::npos || tokenStart > tokenEnd)
+ return;
+
+ string tokenName = cond.substr(tokenStart + 1, tokenEnd - tokenStart - 1);
+ string rest = cond.replace(tokenStart, tokenEnd - tokenStart + 1, "");
+
+ sCondition sCond;
+ sCond.tokenName = tokenName;
+ sCond.type = ctBool;
+ sCond.compareValue = 0;
+ sCond.isNegated = false;
+ if (!rest.compare("not")) {
+ sCond.isNegated = true;
+ } else if (!rest.compare("isset")) {
+ sCond.type = ctStringSet;
+ } else if (startswith(rest.c_str(), "gt(")) {
+ string compVal = rest.substr(4, rest.size() - 5);
+ sCond.compareValue = atoi(compVal.c_str());
+ sCond.type = ctGreater;
+ } else if (startswith(rest.c_str(), "lt(")) {
+ string compVal = rest.substr(4, rest.size() - 5);
+ sCond.compareValue = atoi(compVal.c_str());
+ sCond.type = ctLower;
+ } else if (startswith(rest.c_str(), "eq(")) {
+ string compVal = rest.substr(4, rest.size() - 5);
+ sCond.compareValue = atoi(compVal.c_str());
+ sCond.type = ctEquals;
+ }
+
+ conditions.push_back(sCond);
+}
+
+void cConditionalParameter::Debug(void) {
+ dsyslog("skindesigner: Condition %s, Type: %s, cond is %s", value.c_str(), (type == cpAnd)?"and combination":((type == cpOr)?"or combination":"single param") , isTrue?"true":"false");
+ for (vector<sCondition>::iterator it = conditions.begin(); it != conditions.end(); it++) {
+ dsyslog("skindesigner: cond token %s, type: %d, compareValue %d, negated: %d", it->tokenName.c_str(), it->type, it->compareValue, it->isNegated);
+ }
+} \ No newline at end of file
diff --git a/libtemplate/parameter.h b/libtemplate/parameter.h
new file mode 100644
index 0000000..914f3fc
--- /dev/null
+++ b/libtemplate/parameter.h
@@ -0,0 +1,138 @@
+#ifndef __TEMPLATEPARAMETER_H
+#define __TEMPLATEPARAMETER_H
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <algorithm>
+#include <math.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <sstream>
+
+#include "globals.h"
+
+using namespace std;
+
+enum eAlign {
+ alLeft,
+ alCenter,
+ alRight,
+ alTop,
+ alBottom
+};
+
+enum eScrollMode {
+ smNone,
+ smCarriageReturn,
+ smForthAndBack
+};
+
+enum eScrollSpeed {
+ ssNone,
+ ssSlow,
+ ssMedium,
+ ssFast
+};
+
+enum eOrientation {
+ orNone,
+ orHorizontal,
+ orVertical,
+ orAbsolute
+};
+
+// --- cNumericParameter -------------------------------------------------------------
+
+class cNumericParameter {
+private:
+ cGlobals *globals;
+ string value;
+ bool isValid;
+ int width;
+ int height;
+ int columnWidth;
+ int rowHeight;
+ bool hor;
+ int defaultValue;
+ bool IsNumber(const string& s);
+ bool CheckPercentValue(int &val);
+ bool CheckExpression(int &val, string &parsedVal);
+ bool ValidNumericExpression(string &parsedValue);
+ int EvaluateTheExpression(char* expr);
+ double ParseAtom(char*& expr);
+ double ParseFactors(char*& expr);
+ double ParseSummands(char*& expr);
+public:
+ cNumericParameter(string value);
+ virtual ~cNumericParameter(void);
+ void SetGlobals(cGlobals *globals) { this->globals = globals; };
+ void SetAreaSize(int w, int h);
+ void SetLoopContainer(int columnWidth, int rowHeight) { this->columnWidth = columnWidth; this->rowHeight = rowHeight; };
+ void SetDefault(int def) { defaultValue = def; };
+ void SetHorizontal(void) { hor = true; };
+ void SetVertical(void) { hor = false; };
+ int Parse(string &parsedValue);
+ bool Valid(void) { return isValid; };
+};
+
+// --- cTextToken -------------------------------------------------------------
+
+enum eTextTokenType {
+ ttConstString,
+ ttToken,
+ ttConditionalToken
+};
+
+class cTextToken {
+public:
+ eTextTokenType type;
+ string value;
+ vector<cTextToken> subTokens;
+};
+
+// --- cConditionalParameter -------------------------------------------------------------
+
+enum eCondParameterType {
+ cpAnd,
+ cpOr,
+ cpNone
+};
+
+enum eCondType {
+ ctLower,
+ ctGreater,
+ ctEquals,
+ ctBool,
+ ctStringSet,
+ ctNone
+};
+
+struct sCondition {
+ string tokenName;
+ bool isNegated;
+ eCondType type;
+ int compareValue;
+};
+
+class cConditionalParameter {
+private:
+ cGlobals *globals;
+ bool isTrue;
+ string value;
+ eCondParameterType type;
+ vector<sCondition> conditions;
+ void TokenizeValue(string sep);
+ void InsertCondition(string cond);
+ int EvaluateParameter(string token, map < string, int > *intTokens, map < string, string > *stringTokens);
+public:
+ cConditionalParameter(cGlobals *globals, string value);
+ virtual ~cConditionalParameter(void);
+ void Tokenize(void);
+ bool Evaluate(map < string, int > *intTokens, map < string, string > *stringTokens);
+ bool IsTrue(void) { return isTrue; };
+ void Debug(void);
+};
+#endif //__TEMPLATEPARAMETER_H \ No newline at end of file
diff --git a/libtemplate/template.c b/libtemplate/template.c
new file mode 100644
index 0000000..b5889ad
--- /dev/null
+++ b/libtemplate/template.c
@@ -0,0 +1,273 @@
+ #include "template.h"
+#include "xmlparser.h"
+#include "../config.h"
+
+// --- cTemplate -------------------------------------------------------------
+
+cTemplate::cTemplate(eViewType viewType) {
+ globals = NULL;
+ rootView = NULL;
+ this->viewType = viewType;
+ CreateView();
+}
+
+cTemplate::~cTemplate() {
+
+ if (rootView)
+ delete rootView;
+
+}
+
+/*******************************************************************
+* Public Functions
+*******************************************************************/
+bool cTemplate::ReadFromXML(void) {
+ std::string xmlFile;
+ switch (viewType) {
+ case vtDisplayChannel:
+ xmlFile = "displaychannel.xml";
+ break;
+ case vtDisplayMenu:
+ xmlFile = "displaymenu.xml";
+ break;
+ case vtDisplayMessage:
+ xmlFile = "displaymessage.xml";
+ break;
+ case vtDisplayReplay:
+ xmlFile = "displayreplay.xml";
+ break;
+ case vtDisplayVolume:
+ xmlFile = "displayvolume.xml";
+ break;
+ case vtDisplayAudioTracks:
+ xmlFile = "displayaudiotracks.xml";
+ break;
+ default:
+ return false;
+ }
+
+ cXmlParser parser;
+ if (!parser.ReadView(rootView, xmlFile)) {
+ return false;
+ }
+ if (!parser.ParseView()) {
+ return false;
+ }
+ return true;
+}
+
+void cTemplate::SetGlobals(cGlobals *globals) {
+ this->globals = globals;
+ rootView->SetGlobals(globals);
+}
+
+void cTemplate::Translate(void) {
+ rootView->Translate();
+}
+
+
+void cTemplate::PreCache(void) {
+ rootView->PreCache(false);
+}
+
+vector< pair<string, int> > cTemplate::GetUsedFonts(void) {
+ vector< pair<string, int> > usedFonts;
+
+ GetUsedFonts(rootView, usedFonts);
+
+ rootView->InitSubViewIterator();
+ cTemplateView *subView = NULL;
+ while(subView = rootView->GetNextSubView()) {
+ GetUsedFonts(subView, usedFonts);
+ }
+
+ return usedFonts;
+}
+
+
+void cTemplate::CacheImages(void) {
+ CacheImages(rootView);
+
+ rootView->InitSubViewIterator();
+ cTemplateView *subView = NULL;
+ while(subView = rootView->GetNextSubView()) {
+ CacheImages(subView);
+ }
+}
+
+void cTemplate::Debug(void) {
+
+ rootView->Debug();
+
+}
+
+/*******************************************************************
+* Private Functions
+*******************************************************************/
+
+void cTemplate::CreateView(void) {
+ switch (viewType) {
+ case vtDisplayChannel:
+ rootView = new cTemplateViewChannel();
+ break;
+ case vtDisplayMenu:
+ rootView = new cTemplateViewMenu();
+ break;
+ case vtDisplayReplay:
+ rootView = new cTemplateViewReplay();
+ break;
+ case vtDisplayVolume:
+ rootView = new cTemplateViewVolume();
+ break;
+ case vtDisplayAudioTracks:
+ rootView = new cTemplateViewAudioTracks();
+ break;
+ case vtDisplayMessage:
+ rootView = new cTemplateViewMessage();
+ break;
+ default:
+ esyslog("skindesigner: unknown view %d", viewType);
+ }
+}
+
+void cTemplate::GetUsedFonts(cTemplateView *view, vector< pair<string, int> > &usedFonts) {
+ //used fonts in viewElements
+ view->InitViewElementIterator();
+ cTemplateViewElement *viewElement = NULL;
+ while(viewElement = view->GetNextViewElement()) {
+ viewElement->InitIterator();
+ cTemplatePixmap *pix = NULL;
+ while(pix = viewElement->GetNextPixmap()) {
+ pix->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = pix->GetNextFunction()) {
+ if (func->GetType() == ftDrawText) {
+ usedFonts.push_back(pair<string,int>(func->GetFontName(), func->GetNumericParameter(ptFontSize)));
+ }
+ }
+ }
+ }
+ //used fonts in viewLists pixmaps
+ view->InitViewListIterator();
+ cTemplateViewList *viewList = NULL;
+ while(viewList = view->GetNextViewList()) {
+ viewList->InitIterator();
+ cTemplatePixmap *pix = NULL;
+ while(pix = viewList->GetNextPixmap()) {
+ pix->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = pix->GetNextFunction()) {
+ if (func->GetType() == ftDrawText) {
+ usedFonts.push_back(pair<string,int>(func->GetFontName(), func->GetNumericParameter(ptFontSize)));
+ }
+ }
+ }
+ cTemplateViewElement *listElement = viewList->GetListElement();
+ listElement->InitIterator();
+ while(pix = listElement->GetNextPixmap()) {
+ pix->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = pix->GetNextFunction()) {
+ if (func->GetType() == ftDrawText) {
+ usedFonts.push_back(pair<string,int>(func->GetFontName(), func->GetNumericParameter(ptFontSize)));
+ }
+ }
+ }
+ }
+ //used fonts in viewTabs
+ view->InitViewTabIterator();
+ cTemplateViewTab *viewTab = NULL;
+ while(viewTab = view->GetNextViewTab()) {
+ viewTab->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = viewTab->GetNextFunction()) {
+ if (func->GetType() == ftDrawText) {
+ usedFonts.push_back(pair<string,int>(func->GetFontName(), func->GetNumericParameter(ptFontSize)));
+ }
+ }
+ }
+}
+
+void cTemplate::CacheImages(cTemplateView *view) {
+ //used images in viewElements
+ view->InitViewElementIterator();
+ cTemplateViewElement *viewElement = NULL;
+ while(viewElement = view->GetNextViewElement()) {
+ viewElement->InitIterator();
+ cTemplatePixmap *pix = NULL;
+ while(pix = viewElement->GetNextPixmap()) {
+ pix->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = pix->GetNextFunction()) {
+ if (func->GetType() == ftDrawImage) {
+ CacheImage(func);
+ }
+ }
+ }
+ }
+ //used images in viewLists pixmaps
+ view->InitViewListIterator();
+ cTemplateViewList *viewList = NULL;
+ while(viewList = view->GetNextViewList()) {
+ viewList->InitIterator();
+ cTemplatePixmap *pix = NULL;
+ while(pix = viewList->GetNextPixmap()) {
+ pix->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = pix->GetNextFunction()) {
+ if (func->GetType() == ftDrawImage) {
+ CacheImage(func);
+ }
+ }
+ }
+ cTemplateViewElement *listElement = viewList->GetListElement();
+ listElement->InitIterator();
+ while(pix = listElement->GetNextPixmap()) {
+ pix->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = pix->GetNextFunction()) {
+ if (func->GetType() == ftDrawImage) {
+ CacheImage(func);
+ }
+ }
+ }
+ }
+ //used logos in viewTabs
+ view->InitViewTabIterator();
+ cTemplateViewTab *viewTab = NULL;
+ while(viewTab = view->GetNextViewTab()) {
+ viewTab->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = viewTab->GetNextFunction()) {
+ if (func->GetType() == ftDrawImage) {
+ CacheImage(func);
+ }
+ }
+ }
+}
+
+void cTemplate::CacheImage(cTemplateFunction *func) {
+ eImageType imgType = (eImageType)func->GetNumericParameter(ptImageType);
+ int width = func->GetNumericParameter(ptWidth);
+ int height = func->GetNumericParameter(ptHeight);
+
+ switch (imgType) {
+ case itIcon:
+ case itMenuIcon: {
+ string path = func->GetParameter(ptPath);
+ imgCache->CacheIcon(imgType, path, width, height);
+ break; }
+ case itChannelLogo: {
+ string doCache = func->GetParameter(ptCache);
+ if (!doCache.compare("true")) {
+ imgCache->CacheLogo(width, height);
+ }
+ break; }
+ case itSkinPart: {
+ string path = func->GetParameter(ptPath);
+ imgCache->CacheSkinpart(path, width, height);
+ break; }
+ default:
+ break;
+ }
+}
diff --git a/libtemplate/template.h b/libtemplate/template.h
new file mode 100644
index 0000000..a4ef238
--- /dev/null
+++ b/libtemplate/template.h
@@ -0,0 +1,57 @@
+#ifndef __TEMPLATE_H
+#define __TEMPLATE_H
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <sstream>
+
+#include "globals.h"
+#include "templateview.h"
+#include "templateviewelement.h"
+#include "templatepixmap.h"
+#include "templatefunction.h"
+
+using namespace std;
+
+// --- cTemplate -------------------------------------------------------------
+enum eViewType {
+ vtDisplayChannel,
+ vtDisplayMenu,
+ vtDisplayReplay,
+ vtDisplayVolume,
+ vtDisplayAudioTracks,
+ vtDisplayMessage
+};
+
+class cTemplate {
+private:
+ eViewType viewType;
+ void CacheImage(cTemplateFunction *func);
+protected:
+ cGlobals *globals;
+ cTemplateView *rootView;
+ void CreateView(void);
+ void GetUsedFonts(cTemplateView *view, vector< pair<string, int> > &usedFonts);
+ void CacheImages(cTemplateView *view);
+public:
+ cTemplate(eViewType viewType);
+ virtual ~cTemplate(void);
+ bool ReadFromXML(void);
+ void SetGlobals(cGlobals *globals);
+ cTemplateView *GetRootView(void) { return rootView; };
+ void Translate(void);
+ void PreCache(void);
+ //get fonts for pre caching
+ vector< pair<string, int> > GetUsedFonts(void);
+ void CacheImages(void);
+ //Debug
+ void Debug(void);
+};
+
+#endif //__TEMPLATE_H \ No newline at end of file
diff --git a/libtemplate/templatefunction.c b/libtemplate/templatefunction.c
new file mode 100644
index 0000000..9dca94e
--- /dev/null
+++ b/libtemplate/templatefunction.c
@@ -0,0 +1,1474 @@
+#include "templatefunction.h"
+#include "../config.h"
+#include "../libcore/helpers.h"
+
+using namespace std;
+
+// --- cTemplateFunction -------------------------------------------------------------
+
+cTemplateFunction::cTemplateFunction(eFuncType type) {
+ this->type = type;
+ debug = false;
+ containerX = 0;
+ containerY = 0;
+ containerWidth = 0;
+ containerHeight = 0;
+ columnWidth = -1;
+ rowHeight = -1;
+ globals = NULL;
+ condParam = NULL;
+ parsedCompletely = false;
+ updated = false;
+ alreadyCutted = false;
+ parsedTextWidth = 0;
+ fontName = "";
+ imgPath = "";
+ textboxHeight = 0;
+ stringTokens = NULL;
+ intTokens = NULL;
+ parsedText = "";
+ cuttedText = "";
+}
+
+cTemplateFunction::~cTemplateFunction(void) {
+ if (condParam)
+ delete condParam;
+}
+
+/*******************************************************************
+* Public Functions
+*******************************************************************/
+
+void cTemplateFunction::SetParameters(vector<pair<string, string> > params) {
+ for (vector<pair<string, string> >::iterator it = params.begin(); it != params.end(); it++) {
+ string name = it->first;
+ pair< eParamType, string > p;
+ if (!name.compare("debug")) {
+ string value = it->second;
+ if (!value.compare("true")) {
+ debug = true;
+ }
+ continue;
+ } else if (!name.compare("condition")) {
+ p.first = ptCond;
+ } else if (!name.compare("name")) {
+ p.first = ptName;
+ } else if (!name.compare("x")) {
+ p.first = ptX;
+ } else if (!name.compare("y")) {
+ p.first = ptY;
+ } else if (!name.compare("width")) {
+ p.first = ptWidth;
+ } else if (!name.compare("height")) {
+ p.first = ptHeight;
+ } else if (!name.compare("menuitemwidth")) {
+ p.first = ptMenuItemWidth;
+ } else if (!name.compare("fadetime")) {
+ p.first = ptFadeTime;
+ } else if (!name.compare("imagetype")) {
+ p.first = ptImageType;
+ } else if (!name.compare("path")) {
+ p.first = ptPath;
+ } else if (!name.compare("color")) {
+ p.first = ptColor;
+ } else if (!name.compare("font")) {
+ p.first = ptFont;
+ } else if (!name.compare("fontsize")) {
+ p.first = ptFontSize;
+ } else if (!name.compare("text")) {
+ p.first = ptText;
+ } else if (!name.compare("layer")) {
+ p.first = ptLayer;
+ } else if (!name.compare("transparency")) {
+ p.first = ptTransparency;
+ } else if (!name.compare("quadrant")) {
+ p.first = ptQuadrant;
+ } else if (!name.compare("align")) {
+ p.first = ptAlign;
+ } else if (!name.compare("valign")) {
+ p.first = ptValign;
+ } else if (!name.compare("delay")) {
+ p.first = ptDelay;
+ } else if (!name.compare("mode")) {
+ p.first = ptScrollMode;
+ } else if (!name.compare("scrollspeed")) {
+ p.first = ptScrollSpeed;
+ } else if (!name.compare("orientation")) {
+ p.first = ptOrientation;
+ } else if (!name.compare("numlistelements")) {
+ p.first = ptNumElements;
+ } else if (!name.compare("scrollelement")) {
+ p.first = ptScrollElement;
+ } else if (!name.compare("scrollheight")) {
+ p.first = ptScrollHeight;
+ } else if (!name.compare("float")) {
+ p.first = ptFloat;
+ } else if (!name.compare("floatwidth")) {
+ p.first = ptFloatWidth;
+ } else if (!name.compare("floatheight")) {
+ p.first = ptFloatHeight;
+ } else if (!name.compare("maxlines")) {
+ p.first = ptMaxLines;
+ } else if (!name.compare("columnwidth")) {
+ p.first = ptColumnWidth;
+ } else if (!name.compare("rowheight")) {
+ p.first = ptRowHeight;
+ } else if (!name.compare("overflow")) {
+ p.first = ptOverflow;
+ } else if (!name.compare("scaletvx")) {
+ p.first = ptScaleTvX;
+ } else if (!name.compare("scaletvy")) {
+ p.first = ptScaleTvY;
+ } else if (!name.compare("scaletvwidth")) {
+ p.first = ptScaleTvWidth;
+ } else if (!name.compare("scaletvheight")) {
+ p.first = ptScaleTvHeight;
+ } else if (!name.compare("cache")) {
+ p.first = ptCache;
+ } else if (!name.compare("determinatefont")) {
+ p.first = ptDeterminateFont;
+ } else {
+ p.first = ptNone;
+ }
+ p.second = it->second;
+ nativeParameters.insert(p);
+ }
+}
+
+void cTemplateFunction::SetParameter(eParamType type, string value) {
+ nativeParameters.erase(type);
+ nativeParameters.insert(pair<eParamType, string>(type, value));
+}
+
+void cTemplateFunction::SetContainer(int x, int y, int w, int h) {
+ containerX = x;
+ containerY = y;
+ containerWidth = w;
+ containerHeight = h;
+}
+
+void cTemplateFunction::SetLoopContainer(int columnWidth, int rowHeight) {
+ this->columnWidth = columnWidth;
+ this->rowHeight = rowHeight;
+}
+
+void cTemplateFunction::SetWidthManually(string width) {
+ nativeParameters.erase(ptWidth);
+ nativeParameters.insert(pair<eParamType, string>(ptWidth, width));
+}
+
+void cTemplateFunction::SetHeightManually(string height) {
+ nativeParameters.erase(ptHeight);
+ nativeParameters.insert(pair<eParamType, string>(ptHeight, height));
+}
+
+void cTemplateFunction::SetXManually(int newX) {
+ numericParameters.erase(ptX);
+ numericParameters.insert(pair<eParamType, int>(ptX, newX));
+}
+
+void cTemplateFunction::SetYManually(int newY) {
+ numericParameters.erase(ptY);
+ numericParameters.insert(pair<eParamType, int>(ptY, newY));
+}
+
+void cTemplateFunction::SetTextboxHeight(int boxHeight) {
+ numericParameters.erase(ptHeight);
+ numericParameters.insert(pair<eParamType, int>(ptHeight, boxHeight));
+}
+
+void cTemplateFunction::SetTranslatedText(string translation) {
+ if (type != ftDrawText && type != ftDrawTextBox)
+ return;
+ if (translation.size() == 0)
+ return;
+ nativeParameters.erase(ptText);
+ nativeParameters.insert(pair<eParamType, string>(ptText, translation));
+}
+
+void cTemplateFunction::SetMaxTextWidth(int maxWidth) {
+ if (type != ftDrawText)
+ return;
+ numericParameters.erase(ptWidth);
+ numericParameters.insert(pair<eParamType, int>(ptWidth, maxWidth));
+}
+
+bool cTemplateFunction::CalculateParameters(void) {
+ bool paramValid = true;
+ bool paramsValid = true;
+ for (map< eParamType, string >::iterator param = nativeParameters.begin(); param != nativeParameters.end(); param++) {
+ paramValid = true;
+ eParamType type = param->first;
+ string value = param->second;
+ switch (type) {
+ case ptCond:
+ paramValid = SetCondition(value);
+ break;
+ case ptX:
+ case ptY:
+ case ptWidth:
+ case ptHeight:
+ case ptMenuItemWidth:
+ case ptFadeTime:
+ case ptDelay:
+ case ptFontSize:
+ case ptLayer:
+ case ptTransparency:
+ case ptQuadrant:
+ case ptNumElements:
+ case ptFloatWidth:
+ case ptFloatHeight:
+ case ptMaxLines:
+ case ptColumnWidth:
+ case ptRowHeight:
+ case ptScaleTvX:
+ case ptScaleTvY:
+ case ptScaleTvWidth:
+ case ptScaleTvHeight:
+ SetNumericParameter(type, value);
+ break;
+ case ptAlign:
+ case ptValign:
+ paramValid = SetAlign(type, value);
+ break;
+ case ptImageType:
+ paramValid = SetImageType(type, value);
+ break;
+ case ptColor:
+ paramValid = SetColor(type, value);
+ break;
+ case ptFont:
+ paramValid = SetFont(type, value);
+ break;
+ case ptText:
+ paramValid = SetTextTokens(value);
+ break;
+ case ptScrollMode:
+ paramValid = SetScrollMode(value);
+ break;
+ case ptScrollSpeed:
+ paramValid = SetScrollSpeed(value);
+ break;
+ case ptOrientation:
+ paramValid = SetOrientation(value);
+ break;
+ case ptFloat:
+ paramValid = SetFloating(value);
+ break;
+ case ptOverflow:
+ paramValid = SetOverflow(value);
+ default:
+ paramValid = true;
+ break;
+ }
+ if (!paramValid) {
+ paramsValid = false;
+ esyslog("skindesigner: %s: invalid parameter %d, value %s", GetFuncName().c_str(), type, value.c_str());
+ }
+ }
+ return paramsValid;
+}
+
+void cTemplateFunction::CompleteParameters(void) {
+ switch (type) {
+ case ftDrawImage: {
+ //Calculate img size
+ if ((GetNumericParameter(ptImageType) == itChannelLogo)||(GetNumericParameter(ptImageType) == itSepLogo)) {
+ int logoWidthOrig = config.logoWidth;
+ int logoHeightOrig = config.logoHeight;
+ int logoWidth = GetNumericParameter(ptWidth);
+ int logoHeight = GetNumericParameter(ptHeight);
+ if (logoWidth <= 0 && logoHeight <= 0)
+ break;
+ if (logoWidth <= 0 && logoHeightOrig > 0) {
+ logoWidth = logoHeight * logoWidthOrig / logoHeightOrig;
+ numericParameters.erase(ptWidth);
+ numericParameters.insert(pair<eParamType,int>(ptWidth, logoWidth));
+ } else if (logoHeight <= 0 && logoWidthOrig > 0) {
+ logoHeight = logoWidth * logoHeightOrig / logoWidthOrig;
+ numericParameters.erase(ptHeight);
+ numericParameters.insert(pair<eParamType,int>(ptHeight, logoHeight));
+ }
+ }
+ CalculateAlign(GetNumericParameter(ptWidth), GetNumericParameter(ptHeight));
+ if (imgPath.size() == 0) {
+ imgPath = GetParameter(ptPath);
+ }
+ break; }
+ case ftDrawRectangle:
+ CalculateAlign(GetNumericParameter(ptWidth), GetNumericParameter(ptHeight));
+ break;
+ case ftDrawEllipse:
+ CalculateAlign(GetNumericParameter(ptWidth), GetNumericParameter(ptHeight));
+ break;
+ case ftDrawText:
+ CalculateAlign(GetWidth(), GetHeight());
+ break;
+ default:
+ break;
+ }
+}
+
+void cTemplateFunction::ClearDynamicParameters(void) {
+ parsedText = "";
+ cuttedText = "";
+ alreadyCutted = false;
+ parsedTextWidth = 0;
+ textboxHeight = 0;
+
+ //clear dynamically parsed int parameters
+ for (map<eParamType,string>::iterator it = numericDynamicParameters.begin(); it != numericDynamicParameters.end(); it++) {
+ numericParameters.erase(it->first);
+ }
+ //restoring dynamic numeric parameters only if x, y, width or height of other elements is needed dynamically
+ for (map<eParamType,string>::iterator it = nativeParameters.begin(); it != nativeParameters.end(); it++) {
+ eParamType paramType = it->first;
+ if (paramType == ptX ||
+ paramType == ptY ||
+ paramType == ptWidth ||
+ paramType == ptHeight ||
+ paramType == ptFloatWidth ||
+ paramType == ptFloatHeight)
+ {
+ string value = it->second;
+ if (value.find("{width(") != string::npos || value.find("{height(") != string::npos || value.find("{posx(") != string::npos || value.find("{posy(") != string::npos) {
+ numericDynamicParameters.erase(paramType);
+ SetNumericParameter(paramType, value);
+ }
+ }
+ }
+
+}
+
+bool cTemplateFunction::ParseParameters(void) {
+ updated = false;
+ parsedCompletely = true;
+
+ if (stringTokens) {
+ ParseStringParameters();
+ }
+
+ if (intTokens && numericDynamicParameters.size() > 0) {
+ ParseNumericalParameters();
+ }
+
+ if (condParam) {
+ condParam->Evaluate(intTokens, stringTokens);
+ }
+
+ return parsedCompletely;
+}
+
+string cTemplateFunction::GetParameter(eParamType type) {
+ map<eParamType,string>::iterator hit = nativeParameters.find(type);
+ if (hit == nativeParameters.end())
+ return "";
+ return hit->second;
+}
+
+int cTemplateFunction::GetNumericParameter(eParamType type) {
+ map<eParamType,int>::iterator hit = numericParameters.find(type);
+ if (hit == numericParameters.end()) {
+ //Set Default Value for Integer Parameters
+ if (type == ptLayer)
+ return 1;
+ else if (type == ptTransparency)
+ return 0;
+ else if (type == ptDelay)
+ return 0;
+ else if (type == ptFadeTime)
+ return 0;
+ else if (type == ptMenuItemWidth)
+ return 0;
+ return -1;
+ }
+ return hit->second;
+}
+
+string cTemplateFunction::GetText(bool cut) {
+ if (!cut) {
+ return parsedText;
+ }
+ if (alreadyCutted && cuttedText.size() > 0) {
+ return cuttedText;
+ }
+ alreadyCutted = true;
+ int maxWidth = GetNumericParameter(ptWidth);
+ if (maxWidth > 0) {
+ parsedTextWidth = fontManager->Width(fontName, GetNumericParameter(ptFontSize), parsedText.c_str());
+ if (parsedTextWidth > maxWidth) {
+ cuttedText = CutText(parsedText, maxWidth, fontName, GetNumericParameter(ptFontSize));
+ return cuttedText;
+ }
+ }
+ return parsedText;
+}
+
+
+tColor cTemplateFunction::GetColorParameter(eParamType type) {
+ map<eParamType,tColor>::iterator hit = colorParameters.find(type);
+ if (hit == colorParameters.end())
+ return 0x00000000;
+ return hit->second;
+}
+
+int cTemplateFunction::GetWidth(bool cutted) {
+ int funcWidth = 0;
+ switch (type) {
+ case ftDrawText: {
+ if (cutted) {
+ if (!alreadyCutted) {
+ alreadyCutted = true;
+ int maxWidth = GetNumericParameter(ptWidth);
+ if (maxWidth > 0) {
+ parsedTextWidth = fontManager->Width(fontName, GetNumericParameter(ptFontSize), parsedText.c_str());
+ if (parsedTextWidth > maxWidth) {
+ cuttedText = CutText(parsedText, maxWidth, fontName, GetNumericParameter(ptFontSize));
+ }
+ }
+ }
+ if (cuttedText.size() > 0)
+ return fontManager->Width(fontName, GetNumericParameter(ptFontSize), cuttedText.c_str());
+ }
+ if (parsedTextWidth > 0)
+ funcWidth = parsedTextWidth;
+ else
+ funcWidth = fontManager->Width(fontName, GetNumericParameter(ptFontSize), parsedText.c_str());
+ break; }
+ case ftFill:
+ case ftDrawImage:
+ case ftDrawRectangle:
+ case ftDrawEllipse:
+ case ftDrawTextBox:
+ funcWidth = GetNumericParameter(ptWidth);
+ break;
+ default:
+ esyslog("skindesigner: GetWidth not implemented for funcType %d", type);
+ break;
+ }
+ return funcWidth;
+}
+
+int cTemplateFunction::GetHeight(void) {
+ int funcHeight = 0;
+ switch (type) {
+ case ftDrawText:
+ funcHeight = fontManager->Height(fontName, GetNumericParameter(ptFontSize));
+ break;
+ case ftFill:
+ case ftDrawImage:
+ case ftDrawRectangle:
+ case ftDrawEllipse:
+ funcHeight = GetNumericParameter(ptHeight);
+ break;
+ case ftDrawTextBox: {
+ int maxLines = GetNumericParameter(ptMaxLines);
+ int fixedBoxHeight = GetNumericParameter(ptHeight);
+ if (maxLines > 0) {
+ funcHeight = maxLines * fontManager->Height(fontName, GetNumericParameter(ptFontSize));
+ } else if (fixedBoxHeight > 0) {
+ funcHeight = fixedBoxHeight;
+ } else if (textboxHeight > 0) {
+ funcHeight = textboxHeight;
+ } else {
+ funcHeight = CalculateTextBoxHeight();
+ textboxHeight = funcHeight;
+ }
+ break; }
+ case ftLoop:
+ //TODO: to be implemented
+ break;
+ default:
+ esyslog("skindesigner: GetHeight not implemented for funcType %d", type);
+ break;
+ }
+ return funcHeight;
+}
+
+void cTemplateFunction::GetNeededWidths(multimap<eParamType,string> *widths) {
+ for (map<eParamType, string>::iterator param = numericDynamicParameters.begin(); param !=numericDynamicParameters.end(); param++) {
+ string val = param->second;
+ size_t posStart = val.find("{width(");
+ while (posStart != string::npos) {
+ size_t posEnd = val.find(")", posStart+1);
+ if (posEnd != string::npos) {
+ string label = val.substr(posStart+7, posEnd - posStart - 7);
+ widths->insert(pair<eParamType,string>(param->first, label));
+ val = val.replace(posStart, posEnd - posStart, "");
+ } else {
+ break;
+ }
+ posStart = val.find("{width(");
+ }
+ }
+}
+
+void cTemplateFunction::GetNeededHeights(multimap<eParamType,string> *heights) {
+ for (map<eParamType, string>::iterator param = numericDynamicParameters.begin(); param !=numericDynamicParameters.end(); param++) {
+ string val = param->second;
+ size_t posStart = val.find("{height(");
+ while (posStart != string::npos) {
+ size_t posEnd = val.find(")", posStart + 1);
+ if (posEnd != string::npos) {
+ string label = val.substr(posStart + 8, posEnd - posStart - 8);
+ heights->insert(pair<eParamType,string>(param->first, label));
+ val = val.replace(posStart, posEnd - posStart, "");
+ } else {
+ break;
+ }
+ posStart = val.find("{height(");
+ }
+ }
+}
+
+void cTemplateFunction::GetNeededPosX(multimap<eParamType,string> *posXs) {
+ for (map<eParamType, string>::iterator param = numericDynamicParameters.begin(); param !=numericDynamicParameters.end(); param++) {
+ string val = param->second;
+ size_t posStart = val.find("{posx(");
+ while (posStart != string::npos) {
+ size_t posEnd = val.find(")", posStart+1);
+ if (posEnd != string::npos) {
+ string label = val.substr(posStart+6, posEnd - posStart - 6);
+ posXs->insert(pair<eParamType,string>(param->first, label));
+ val = val.replace(posStart, posEnd - posStart, "");
+ } else {
+ break;
+ }
+ posStart = val.find("{posx(");
+ }
+ }
+}
+
+void cTemplateFunction::GetNeededPosY(multimap<eParamType,string> *posYs) {
+ for (map<eParamType, string>::iterator param = numericDynamicParameters.begin(); param !=numericDynamicParameters.end(); param++) {
+ string val = param->second;
+ size_t posStart = val.find("{posy(");
+ while (posStart != string::npos) {
+ size_t posEnd = val.find(")", posStart+1);
+ if (posEnd != string::npos) {
+ string label = val.substr(posStart+6, posEnd - posStart - 6);
+ posYs->insert(pair<eParamType,string>(param->first, label));
+ val = val.replace(posStart, posEnd - posStart, "");
+ } else {
+ break;
+ }
+ posStart = val.find("{posy(");
+ }
+ }
+}
+
+void cTemplateFunction::SetWidth(eParamType type, string label, int funcWidth) {
+ updated = false;
+ map< eParamType, string >::iterator hit = numericDynamicParameters.find(type);
+ if (hit == numericDynamicParameters.end())
+ return;
+ stringstream needle;
+ needle << "{width(" << label << ")}";
+ size_t posFound = (hit->second).find(needle.str());
+ if (posFound == string::npos)
+ return;
+ stringstream repl;
+ repl << funcWidth;
+ string parsedVal = (hit->second).replace(posFound, needle.str().size(), repl.str());
+
+ cNumericParameter param(parsedVal);
+ param.SetAreaSize(containerWidth, containerHeight);
+ param.SetGlobals(globals);
+ int val = param.Parse(parsedVal);
+ if (param.Valid()) {
+ updated = true;
+ numericParameters.insert(pair<eParamType, int>(type, val));
+ } else {
+ numericDynamicParameters.erase(type);
+ numericDynamicParameters.insert(pair<eParamType, string>(type, parsedVal));
+ }
+}
+
+void cTemplateFunction::SetHeight(eParamType type, string label, int funcHeight) {
+ updated = false;
+ map< eParamType, string >::iterator hit = numericDynamicParameters.find(type);
+ if (hit == numericDynamicParameters.end())
+ return;
+ stringstream needle;
+ needle << "{height(" << label << ")}";
+ size_t posFound = (hit->second).find(needle.str());
+ if (posFound == string::npos)
+ return;
+ stringstream repl;
+ repl << funcHeight;
+ string parsedVal = (hit->second).replace(posFound, needle.str().size(), repl.str());
+
+ cNumericParameter param(parsedVal);
+ param.SetAreaSize(containerWidth, containerHeight);
+ param.SetGlobals(globals);
+ int val = param.Parse(parsedVal);
+ if (param.Valid()) {
+ updated = true;
+ numericParameters.insert(pair<eParamType, int>(type, val));
+ } else {
+ numericDynamicParameters.erase(type);
+ numericDynamicParameters.insert(pair<eParamType, string>(type, parsedVal));
+ }
+}
+
+void cTemplateFunction::SetX(eParamType type, string label, int funcX) {
+ updated = false;
+ map< eParamType, string >::iterator hit = numericDynamicParameters.find(type);
+ if (hit == numericDynamicParameters.end())
+ return;
+ stringstream needle;
+ needle << "{posx(" << label << ")}";
+ size_t posFound = (hit->second).find(needle.str());
+ if (posFound == string::npos)
+ return;
+ stringstream repl;
+ repl << funcX;
+ string parsedVal = (hit->second).replace(posFound, needle.str().size(), repl.str());
+
+ cNumericParameter param(parsedVal);
+ param.SetAreaSize(containerWidth, containerHeight);
+ param.SetGlobals(globals);
+ int val = param.Parse(parsedVal);
+ if (param.Valid()) {
+ updated = true;
+ numericParameters.insert(pair<eParamType, int>(type, val));
+ } else {
+ numericDynamicParameters.erase(type);
+ numericDynamicParameters.insert(pair<eParamType, string>(type, parsedVal));
+ }
+}
+
+void cTemplateFunction::SetY(eParamType type, string label, int funcY) {
+ updated = false;
+ map< eParamType, string >::iterator hit = numericDynamicParameters.find(type);
+ if (hit == numericDynamicParameters.end())
+ return;
+ stringstream needle;
+ needle << "{posy(" << label << ")}";
+ size_t posFound = (hit->second).find(needle.str());
+ if (posFound == string::npos)
+ return;
+ stringstream repl;
+ repl << funcY;
+ string parsedVal = (hit->second).replace(posFound, needle.str().size(), repl.str());
+
+ cNumericParameter param(parsedVal);
+ param.SetAreaSize(containerWidth, containerHeight);
+ param.SetGlobals(globals);
+ int val = param.Parse(parsedVal);
+ if (param.Valid()) {
+ updated = true;
+ numericParameters.insert(pair<eParamType, int>(type, val));
+ } else {
+ numericDynamicParameters.erase(type);
+ numericDynamicParameters.insert(pair<eParamType, string>(type, parsedVal));
+ }
+}
+
+bool cTemplateFunction::DoExecute(void) {
+ if (!condParam)
+ return true;
+ return condParam->IsTrue();
+}
+
+/*******************************************************************
+* Private Functions
+*******************************************************************/
+
+bool cTemplateFunction::SetCondition(string cond) {
+ if (condParam)
+ delete condParam;
+ condParam = new cConditionalParameter(globals, cond);
+ condParam->Tokenize();
+ return true;
+}
+
+
+bool cTemplateFunction::SetNumericParameter(eParamType type, string value) {
+ if (config.replaceDecPoint) {
+ if (value.find_first_of('.') != string::npos) {
+ std::replace( value.begin(), value.end(), '.', config.decPoint);
+ }
+ }
+
+ cNumericParameter param(value);
+ param.SetAreaSize(containerWidth, containerHeight);
+ param.SetLoopContainer(columnWidth, rowHeight);
+ param.SetGlobals(globals);
+ switch (type) {
+ case ptX:
+ case ptWidth:
+ case ptMenuItemWidth:
+ case ptScaleTvX:
+ case ptScaleTvWidth:
+ param.SetHorizontal();
+ break;
+ case ptY:
+ case ptHeight:
+ case ptFontSize:
+ case ptScaleTvY:
+ case ptScaleTvHeight:
+ param.SetVertical();
+ break;
+ case ptLayer:
+ param.SetDefault(1);
+ break;
+ default:
+ break;
+ }
+ string parsedValue = "";
+ int val = param.Parse(parsedValue);
+ if (param.Valid()) {
+ if (this->type < ftLoop && type == ptX) {
+ val += containerX;
+ }
+ if (this->type < ftLoop && type == ptY) {
+ val += containerY;
+ }
+ numericParameters.insert(pair<eParamType, int>(type, val));
+ } else {
+ numericDynamicParameters.insert(pair<eParamType, string>(type, parsedValue));
+ }
+ return param.Valid();
+}
+
+bool cTemplateFunction::SetAlign(eParamType type, string value) {
+ eAlign align = alLeft;
+ bool ok = true;
+ if (!value.compare("center")) {
+ align = alCenter;
+ } else if (!value.compare("right")) {
+ align = alRight;
+ } else if (!value.compare("top")) {
+ align = alTop;
+ } else if (!value.compare("bottom")) {
+ align = alBottom;
+ } else if (!value.compare("left")) {
+ align = alLeft;
+ } else {
+ ok = false;
+ }
+ numericParameters.insert(pair<eParamType, int>(type, align));
+ return ok;
+}
+
+bool cTemplateFunction::SetFont(eParamType type, string value) {
+ //check if token
+ if ((value.find("{") == 0) && (value.find("}") == (value.size()-1))) {
+ value = value.substr(1, value.size()-2);
+ map<string,string>::iterator hit = globals->fonts.find(value);
+ if (hit != globals->fonts.end()) {
+ fontName = hit->second;
+ } else {
+ map<string,string>::iterator def = globals->fonts.find("vdrOsd");
+ if (def == globals->fonts.end())
+ return false;
+ fontName = def->second;
+ }
+ } else {
+ //if no token, directly use input
+ fontName = value;
+ }
+ return true;
+}
+
+bool cTemplateFunction::SetImageType(eParamType type, string value) {
+ eImageType imgType = itImage;
+ bool ok = true;
+ if (!value.compare("channellogo")) {
+ imgType = itChannelLogo;
+ } else if (!value.compare("seplogo")) {
+ imgType = itSepLogo;
+ } else if (!value.compare("skinpart")) {
+ imgType = itSkinPart;
+ } else if (!value.compare("menuicon")) {
+ imgType = itMenuIcon;
+ } else if (!value.compare("icon")) {
+ imgType = itIcon;
+ } else if (!value.compare("image")) {
+ imgType = itImage;
+ } else {
+ ok = false;
+ }
+ numericParameters.insert(pair<eParamType, int>(ptImageType, imgType));
+ return ok;
+}
+
+
+bool cTemplateFunction::SetColor(eParamType type, string value) {
+ if (globals) {
+ for (map<string, tColor>::iterator col = globals->colors.begin(); col != globals->colors.end(); col++) {
+ stringstream sColName;
+ sColName << "{" << col->first << "}";
+ string colName = sColName.str();
+ if (!colName.compare(value)) {
+ tColor colVal = col->second;
+ colorParameters.insert(pair<eParamType, tColor>(type, colVal));
+ return true;
+ }
+ }
+ }
+ if (value.size() != 8)
+ return false;
+ std::stringstream str;
+ str << value;
+ tColor colVal;
+ str >> std::hex >> colVal;
+ colorParameters.insert(pair<eParamType, tColor>(type, colVal));
+ return true;
+}
+
+bool cTemplateFunction::SetTextTokens(string value) {
+ textTokens.clear();
+ //first replace globals
+ for (map<string,string>::iterator globStr = globals->stringVars.begin(); globStr != globals->stringVars.end(); globStr++) {
+ stringstream sToken;
+ sToken << "{" << globStr->first << "}";
+ string token = sToken.str();
+ size_t foundToken = value.find(token);
+ if (foundToken != string::npos) {
+ value = value.replace(foundToken, token.size(), globStr->second);
+ }
+ }
+ //now tokenize
+ bool tokenFound = true;
+ while (tokenFound) {
+ //search for conditional token or normal token
+ size_t tokenStart = value.find_first_of('{');
+ size_t conditionStart = value.find_first_of('|');
+ if (tokenStart == string::npos && conditionStart == string::npos) {
+ if (value.size() > 0) {
+ cTextToken token;
+ token.type = ttConstString;
+ token.value = value;
+ textTokens.push_back(token);
+ }
+ tokenFound = false;
+ continue;
+ } else if (tokenStart != string::npos && conditionStart == string::npos) {
+ size_t tokenEnd = value.find_first_of('}');
+ ParseTextToken(value, tokenStart, tokenEnd);
+ } else if (tokenStart != string::npos && conditionStart != string::npos) {
+ if (tokenStart < conditionStart) {
+ size_t tokenEnd = value.find_first_of('}');
+ ParseTextToken(value, tokenStart, tokenEnd);
+ } else {
+ size_t conditionEnd = value.find_first_of('|', conditionStart+1);
+ ParseConditionalTextToken(value, conditionStart, conditionEnd);
+ }
+ }
+ }
+ return true;
+}
+
+void cTemplateFunction::ParseTextToken(string &value, size_t start, size_t end) {
+ cTextToken token;
+ if (start > 0) {
+ string constString = value.substr(0, start);
+ value = value.replace(0, start, "");
+ token.type = ttConstString;
+ token.value = constString;
+ textTokens.push_back(token);
+ } else {
+ string tokenName = value.substr(1, end - start - 1);
+ value = value.replace(0, end - start + 1, "");
+ token.type = ttToken;
+ token.value = tokenName;
+ textTokens.push_back(token);
+ }
+}
+
+void cTemplateFunction::ParseConditionalTextToken(string &value, size_t start, size_t end) {
+ cTextToken token;
+ if (start > 0) {
+ string constString = value.substr(0, start);
+ value = value.replace(0, start, "");
+ token.type = ttConstString;
+ token.value = constString;
+ textTokens.push_back(token);
+ } else {
+ string condToken = value.substr(start + 1, end - start - 1);
+ value = value.replace(0, end - start + 1, "");
+ size_t tokenStart = condToken.find_first_of('{');
+ size_t tokenEnd = condToken.find_first_of('}');
+ vector<cTextToken> subTokens;
+ if (tokenStart > 0) {
+ cTextToken subToken;
+ string constString = condToken.substr(0, tokenStart);
+ condToken = condToken.replace(0, tokenStart, "");
+ subToken.type = ttConstString;
+ subToken.value = constString;
+ subTokens.push_back(subToken);
+ }
+ string tokenName = condToken.substr(1, tokenEnd - tokenStart - 1);
+ condToken = condToken.replace(0, tokenEnd - tokenStart + 1, "");
+
+ cTextToken subToken2;
+ subToken2.type = ttToken;
+ subToken2.value = tokenName;
+ subTokens.push_back(subToken2);
+
+ if (condToken.size() > 0) {
+ cTextToken subToken3;
+ subToken3.type = ttConstString;
+ subToken3.value = condToken;
+ subTokens.push_back(subToken3);
+ }
+
+ token.type = ttConditionalToken;
+ token.value = tokenName;
+ token.subTokens = subTokens;
+ textTokens.push_back(token);
+ }
+
+}
+
+bool cTemplateFunction::SetScrollMode(string value) {
+ eScrollMode mode = smNone;
+ bool ok = true;
+ if (!value.compare("forthandback"))
+ mode = smForthAndBack;
+ else if (!value.compare("carriagereturn"))
+ mode = smCarriageReturn;
+ else
+ ok = false;
+ numericParameters.insert(pair<eParamType, int>(ptScrollMode, mode));
+ return ok;
+}
+
+bool cTemplateFunction::SetScrollSpeed(string value) {
+ eScrollSpeed speed = ssMedium;
+ bool ok = true;
+ if (!value.compare("slow"))
+ speed = ssSlow;
+ else if (!value.compare("fast"))
+ speed = ssFast;
+ else if (!value.compare("medium"))
+ speed = ssMedium;
+ else
+ ok = false;
+ numericParameters.insert(pair<eParamType, int>(ptScrollSpeed, speed));
+ return ok;
+
+}
+
+bool cTemplateFunction::SetOrientation(string value) {
+ eOrientation orientation = orNone;
+ bool ok = true;
+ if (!value.compare("horizontal"))
+ orientation = orHorizontal;
+ else if (!value.compare("vertical"))
+ orientation = orVertical;
+ else if (!value.compare("absolute"))
+ orientation = orAbsolute;
+ else
+ ok = false;
+ numericParameters.insert(pair<eParamType, int>(ptOrientation, orientation));
+ return ok;
+}
+
+bool cTemplateFunction::SetFloating(string value) {
+ eFloatType floatType = flNone;
+ bool ok = true;
+ if (!value.compare("topleft"))
+ floatType = flTopLeft;
+ else if (!value.compare("topright"))
+ floatType = flTopRight;
+ else
+ ok = false;
+ numericParameters.insert(pair<eParamType, int>(ptFloat, floatType));
+ return ok;
+}
+
+bool cTemplateFunction::SetOverflow(string value) {
+ eOverflowType overflowType = otNone;
+ bool ok = true;
+ if (!value.compare("linewrap"))
+ overflowType = otWrap;
+ else if (!value.compare("cut"))
+ overflowType = otCut;
+ else
+ ok = false;
+ numericParameters.insert(pair<eParamType, int>(ptOverflow, overflowType));
+ return ok;
+}
+
+void cTemplateFunction::ParseStringParameters(void) {
+ //first replace stringtokens in Text (drawText)
+ stringstream text;
+ for (vector<cTextToken>::iterator it = textTokens.begin(); it !=textTokens.end(); it++) {
+ updated = true;
+ if ((*it).type == ttConstString) {
+ text << (*it).value;
+ } else if ((*it).type == ttToken) {
+ bool found = false;
+ string tokenName = (*it).value;
+ if (stringTokens) {
+ map < string, string >::iterator hit = stringTokens->find(tokenName);
+ if (hit != stringTokens->end()) {
+ text << hit->second;
+ found = true;
+ }
+ }
+ if (!found && intTokens) {
+ map < string, int >::iterator hitInt = intTokens->find(tokenName);
+ if (hitInt != intTokens->end()) {
+ text << hitInt->second;
+ found = true;
+ }
+ }
+ if (!found) {
+ text << "{" << tokenName << "}";
+ }
+ } else if ((*it).type == ttConditionalToken) {
+ bool found = false;
+ string tokenName = (*it).value;
+ if (stringTokens) {
+ map < string, string >::iterator hit = stringTokens->find(tokenName);
+ if (hit != stringTokens->end()) {
+ string replaceText = hit->second;
+ if (replaceText.size() > 0) {
+ for (vector<cTextToken>::iterator it2 = (*it).subTokens.begin(); it2 != (*it).subTokens.end(); it2++) {
+ if ((*it2).type == ttConstString) {
+ text << (*it2).value;
+ } else {
+ text << replaceText;
+ }
+ }
+ }
+ found = true;
+ }
+ }
+ if (!found && intTokens) {
+ map < string, int >::iterator hitInt = intTokens->find(tokenName);
+ if (hitInt != intTokens->end()) {
+ int intVal = hitInt->second;
+ if (intVal > 0) {
+ for (vector<cTextToken>::iterator it2 = (*it).subTokens.begin(); it2 != (*it).subTokens.end(); it2++) {
+ if ((*it2).type == ttConstString) {
+ text << (*it2).value;
+ } else {
+ text << intVal;
+ }
+ }
+ }
+ found = true;
+ }
+ }
+ }
+ }
+ parsedText = text.str();
+
+ //now check further possible string variables
+ string path = GetParameter(ptPath);
+ if (stringTokens && path.size() > 0 && path.find("{") != string::npos) {
+ for (map < string, string >::iterator it = stringTokens->begin(); it != stringTokens->end(); it++) {
+ size_t found = path.find(it->first);
+ if (found != string::npos) {
+ updated = true;
+ imgPath = path;
+ if (found > 0 && ((it->first).size() + 2 <= imgPath.size()))
+ imgPath.replace(found-1, (it->first).size() + 2, it->second);
+ break;
+ }
+ }
+ }
+}
+
+void cTemplateFunction::ParseNumericalParameters(void) {
+ parsedCompletely = true;
+ for (map<eParamType, string>::iterator param = numericDynamicParameters.begin(); param !=numericDynamicParameters.end(); param++) {
+ string val = param->second;
+ for (map<string,int >::iterator tok = intTokens->begin(); tok != intTokens->end(); tok++) {
+ stringstream sToken;
+ sToken << "{" << tok->first << "}";
+ string token = sToken.str();
+ size_t foundToken = val.find(token);
+ //replace token as often as it appears
+ while (foundToken != string::npos) {
+ stringstream sVal;
+ sVal << tok->second;
+ val = val.replace(foundToken, token.size(), sVal.str());
+ foundToken = val.find(token);
+ }
+ }
+ cNumericParameter p(val);
+ string parsedVal = "";
+ int newVal = p.Parse(parsedVal);
+ if (p.Valid()) {
+ updated = true;
+ numericParameters.insert(pair<eParamType, int>(param->first, newVal));
+ } else {
+ parsedCompletely = false;
+ }
+ }
+}
+
+void cTemplateFunction::CalculateAlign(int elementWidth, int elementHeight) {
+ int align = GetNumericParameter(ptAlign);
+ //if element is used in a loop, use loop box width
+ int boxWidth = (columnWidth > 0) ? columnWidth : containerWidth;
+ int boxHeight = (rowHeight > 0) ? rowHeight : containerHeight;
+ if (align == alCenter) {
+ int xNew = (boxWidth - elementWidth) / 2;
+ numericParameters.erase(ptX);
+ numericParameters.insert(pair<eParamType,int>(ptX, xNew));
+ } else if (align == alRight) {
+ int xNew = boxWidth - elementWidth;
+ numericParameters.erase(ptX);
+ numericParameters.insert(pair<eParamType,int>(ptX, xNew));
+ }
+
+ int vAlign = GetNumericParameter(ptValign);
+ if (vAlign == alCenter) {
+ int yNew = (boxHeight - elementHeight) / 2;
+ numericParameters.erase(ptY);
+ numericParameters.insert(pair<eParamType,int>(ptY, yNew));
+ } else if (vAlign == alBottom) {
+ int yNew = boxHeight - elementHeight;
+ numericParameters.erase(ptY);
+ numericParameters.insert(pair<eParamType,int>(ptY, yNew));
+ }
+}
+
+int cTemplateFunction::CalculateTextBoxHeight(void) {
+ int width = GetNumericParameter(ptWidth);
+ string fontName = GetFontName();
+ int fontSize = GetNumericParameter(ptFontSize);
+ string text = GetText(false);
+ const cFont *font = fontManager->Font(fontName, fontSize);
+ if (!font)
+ return 0;
+
+ int fontHeight = fontManager->Height(fontName, fontSize);
+ int floatType = GetNumericParameter(ptFloat);
+
+ if (floatType == flNone) {
+ cTextWrapper wrapper;
+ wrapper.Set(text.c_str(), font, width);
+ int lines = wrapper.Lines();
+ return (lines * fontHeight);
+ }
+
+ int floatWidth = GetNumericParameter(ptFloatWidth);
+ int floatHeight = GetNumericParameter(ptFloatHeight);
+
+ cTextWrapper wTextTall;
+ cTextWrapper wTextFull;
+
+ int linesNarrow = floatHeight / fontHeight;
+ int widthNarrow = width - floatWidth;
+ int linesDrawn = 0;
+ int curY = 0;
+ bool drawNarrow = true;
+
+ splitstring s(text.c_str());
+ vector<string> flds = s.split('\n', 1);
+
+ if (flds.size() < 1)
+ return 0;
+
+ stringstream sstrTextTall;
+ stringstream sstrTextFull;
+
+ for (int i=0; i<flds.size(); i++) {
+ if (!flds[i].size()) {
+ //empty line
+ linesDrawn++;
+ curY += fontHeight;
+ if (drawNarrow)
+ sstrTextTall << "\n";
+ else
+ sstrTextFull << "\n";
+ } else {
+ cTextWrapper wrapper;
+ if (drawNarrow) {
+ wrapper.Set((flds[i].c_str()), font, widthNarrow);
+ int newLines = wrapper.Lines();
+ //check if wrapper fits completely into narrow area
+ if (linesDrawn + newLines < linesNarrow) {
+ for (int line = 0; line < wrapper.Lines(); line++) {
+ sstrTextTall << wrapper.GetLine(line) << " ";
+ }
+ sstrTextTall << "\n";
+ linesDrawn += newLines;
+ } else {
+ //this wrapper has to be splitted
+ for (int line = 0; line < wrapper.Lines(); line++) {
+ if (line + linesDrawn < linesNarrow) {
+ sstrTextTall << wrapper.GetLine(line) << " ";
+ } else {
+ sstrTextFull << wrapper.GetLine(line) << " ";
+ }
+ }
+ sstrTextFull << "\n";
+ drawNarrow = false;
+ }
+ } else {
+ wrapper.Set((flds[i].c_str()), font, width);
+ for (int line = 0; line < wrapper.Lines(); line++) {
+ sstrTextFull << wrapper.GetLine(line) << " ";
+ }
+ sstrTextFull << "\n";
+ }
+ }
+ }
+ wTextTall.Set(sstrTextTall.str().c_str(), font, widthNarrow);
+ wTextFull.Set(sstrTextFull.str().c_str(), font, width);
+
+ int textLinesTall = wTextTall.Lines();
+ int textLinesFull = wTextFull.Lines();
+
+ return ((textLinesTall+textLinesFull) * fontHeight);
+}
+
+/*******************************************************************
+* Helper Functions
+*******************************************************************/
+
+string cTemplateFunction::GetFuncName(void) {
+ string name;
+ switch (type) {
+ case ftOsd:
+ name = "OSD Parameters";
+ break;
+ case ftView:
+ name = "View Parameters";
+ break;
+ case ftViewElement:
+ name = "View Element Parameters";
+ break;
+ case ftPixmap:
+ name = "Pixmap Parameters";
+ break;
+ case ftPixmapScroll:
+ name = "ScrollPixmap Parameters";
+ break;
+ case ftLoop:
+ name = "Looping Function";
+ break;
+ case ftFill:
+ name = "Function Fill";
+ break;
+ case ftDrawText:
+ name = "Function DrawText";
+ break;
+ case ftDrawTextBox:
+ name = "Function DrawTextBox";
+ break;
+ case ftDrawImage:
+ name = "Function DrawImage";
+ break;
+ case ftDrawRectangle:
+ name = "Function DrawRectangle";
+ break;
+ case ftDrawEllipse:
+ name = "Function DrawEllipse";
+ break;
+ case ftNone:
+ name = "Undefined";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ };
+ return name;
+}
+
+string cTemplateFunction::GetParamName(eParamType pt) {
+ string name;
+ switch (pt) {
+ case ptCond:
+ name = "Condition";
+ break;
+ case ptName:
+ name = "Name";
+ break;
+ case ptX:
+ name = "X";
+ break;
+ case ptY:
+ name = "Y";
+ break;
+ case ptWidth:
+ name = "Width";
+ break;
+ case ptHeight:
+ name = "Height";
+ break;
+ case ptMenuItemWidth:
+ name = "Menu Item Width";
+ break;
+ case ptFadeTime:
+ name = "Fade Time";
+ break;
+ case ptDelay:
+ name = "Delay";
+ break;
+ case ptImageType:
+ name = "Image Type";
+ break;
+ case ptPath:
+ name = "Image Path";
+ break;
+ case ptColor:
+ name = "Color";
+ break;
+ case ptFont:
+ name = "Font";
+ break;
+ case ptFontSize:
+ name = "FontSize";
+ break;
+ case ptText:
+ name = "Text";
+ break;
+ case ptLayer:
+ name = "Layer";
+ break;
+ case ptTransparency:
+ name = "Transparency";
+ break;
+ case ptQuadrant:
+ name = "Quadrant";
+ break;
+ case ptAlign:
+ name = "Align";
+ break;
+ case ptValign:
+ name = "Vertical Align";
+ break;
+ case ptScrollMode:
+ name = "Scroll Mode";
+ break;
+ case ptScrollSpeed:
+ name = "Scroll Speed";
+ break;
+ case ptOrientation:
+ name = "Orientation";
+ break;
+ case ptNumElements:
+ name = "NumElements";
+ break;
+ case ptScrollElement:
+ name = "Scroll Element";
+ break;
+ case ptScrollHeight:
+ name = "Scroll Height";
+ break;
+ case ptFloat:
+ name = "Floating Type";
+ break;
+ case ptFloatWidth:
+ name = "Floating Width";
+ break;
+ case ptFloatHeight:
+ name = "Floating Height";
+ break;
+ case ptMaxLines:
+ name = "Max num of lines";
+ break;
+ case ptColumnWidth:
+ name = "Column Width";
+ break;
+ case ptRowHeight:
+ name = "Row Height";
+ break;
+ case ptOverflow:
+ name = "Overflow Mode";
+ break;
+ case ptScaleTvX:
+ name = "Scale TV Picture X";
+ break;
+ case ptScaleTvY:
+ name = "Scale TV Picture Y";
+ break;
+ case ptScaleTvWidth:
+ name = "Scale TV Picture Width";
+ break;
+ case ptScaleTvHeight:
+ name = "Scale TV Picture Height";
+ break;
+ case ptCache:
+ name = "Cache Image";
+ break;
+ case ptDeterminateFont:
+ name = "Determinate Font";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ };
+ return name;
+}
+
+void cTemplateFunction::Debug(void) {
+ esyslog("skindesigner: Debugging %s, Container: x = %d, y = %d, Size: %dx%d", GetFuncName().c_str(), containerX, containerY, containerWidth, containerHeight);
+ esyslog("skindesigner: --- Native Parameters:");
+
+ if (condParam) {
+ condParam->Debug();
+ }
+ esyslog("skindesigner: --- Native Parameters:");
+ for (map<eParamType,string>::iterator it = nativeParameters.begin(); it != nativeParameters.end(); it++) {
+ esyslog("skindesigner: \"%s\" = \"%s\"", GetParamName(it->first).c_str(), (it->second).c_str());
+ }
+ if (numericParameters.size() > 0) {
+ esyslog("skindesigner: --- Integer Parameters: ");
+ for (map<eParamType,int>::iterator it = numericParameters.begin(); it != numericParameters.end(); it++) {
+ esyslog("skindesigner: %s = %d", GetParamName(it->first).c_str(), it->second);
+ }
+ }
+ if (numericDynamicParameters.size() > 0) {
+ esyslog("skindesigner: --- Dynamic Integer Parameters: ");
+ for (map<eParamType,string>::iterator it = numericDynamicParameters.begin(); it != numericDynamicParameters.end(); it++) {
+ esyslog("skindesigner: %s = %s", GetParamName(it->first).c_str(), (it->second).c_str());
+ }
+ }
+ if (colorParameters.size() > 0) {
+ esyslog("skindesigner: --- Color Parameters:");
+ for (map<eParamType,tColor>::iterator it = colorParameters.begin(); it != colorParameters.end(); it++) {
+ esyslog("skindesigner: %s = %x", GetParamName(it->first).c_str(), it->second);
+ }
+ }
+ if (textTokens.size() > 0) {
+ esyslog("skindesigner: --- Text Tokens:");
+ int i=0;
+ for (vector<cTextToken>::iterator it = textTokens.begin(); it != textTokens.end(); it++) {
+ eTextTokenType tokenType = (*it).type;
+ string tokType = "";
+ if (tokenType == ttConstString)
+ tokType = "Const: ";
+ else if (tokenType == ttToken)
+ tokType = "Token: ";
+ else if (tokenType == ttConditionalToken)
+ tokType = "Conditional Token: ";
+ esyslog("skindesigner: %s %d = \"%s\"", tokType.c_str(), i++, (*it).value.c_str());
+ if (tokenType == ttConditionalToken) {
+ for (vector<cTextToken>::iterator it2 = (*it).subTokens.begin(); it2 != (*it).subTokens.end(); it2++) {
+ eTextTokenType tokenTypeCond = (*it2).type;
+ string tokTypeCond = "";
+ if (tokenTypeCond == ttConstString)
+ tokTypeCond = "Const: ";
+ else if (tokenTypeCond == ttToken)
+ tokTypeCond = "Token: ";
+ esyslog("skindesigner: %s \"%s\"", tokTypeCond.c_str(), (*it2).value.c_str());
+ }
+ }
+ }
+ }
+ if (fontName.size() > 0) {
+ esyslog("skindesigner: --- Font Name: \"%s\"", fontName.c_str());
+ }
+ if (parsedText.size() > 0) {
+ esyslog("skindesigner: --- Parsed Text: \"%s\"", parsedText.c_str());
+ }
+ if (type == ftDrawText) {
+ esyslog("skindesigner: --- Cutted Text: \"%s\"", cuttedText.c_str());
+ esyslog("skindesigner: --- Parsed Text Width: %d", parsedTextWidth);
+ esyslog("skindesigner: --- Already Cutted: %s", alreadyCutted ? "true" : "false");
+ }
+ if (imgPath.size() > 0) {
+ esyslog("skindesigner: --- Image Path: \"%s\"", imgPath.c_str());
+ }
+}
diff --git a/libtemplate/templatefunction.h b/libtemplate/templatefunction.h
new file mode 100644
index 0000000..9a784c5
--- /dev/null
+++ b/libtemplate/templatefunction.h
@@ -0,0 +1,211 @@
+#ifndef __TEMPLATEFUNCTION_H
+#define __TEMPLATEFUNCTION_H
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <sstream>
+
+#include "globals.h"
+#include "parameter.h"
+
+using namespace std;
+
+// --- cTemplateFunction -------------------------------------------------------------
+
+enum eFuncType {
+ ftOsd,
+ ftView,
+ ftViewElement,
+ ftViewList,
+ ftPixmap,
+ ftPixmapScroll,
+ ftLoop,
+ ftFill,
+ ftDrawText,
+ ftDrawTextBox,
+ ftDrawImage,
+ ftDrawRectangle,
+ ftDrawEllipse,
+ ftNone
+};
+
+enum eParamType {
+ ptCond,
+ ptName,
+ ptX,
+ ptY,
+ ptWidth,
+ ptHeight,
+ ptMenuItemWidth,
+ ptFadeTime,
+ ptDelay,
+ ptImageType,
+ ptPath,
+ ptColor,
+ ptFont,
+ ptFontSize,
+ ptText,
+ ptLayer,
+ ptTransparency,
+ ptQuadrant,
+ ptAlign,
+ ptValign,
+ ptScrollMode,
+ ptScrollSpeed,
+ ptOrientation,
+ ptNumElements,
+ ptScrollElement,
+ ptScrollHeight,
+ ptFloat,
+ ptFloatWidth,
+ ptFloatHeight,
+ ptMaxLines,
+ ptColumnWidth,
+ ptRowHeight,
+ ptOverflow,
+ ptScaleTvX,
+ ptScaleTvY,
+ ptScaleTvWidth,
+ ptScaleTvHeight,
+ ptCache,
+ ptDeterminateFont,
+ ptNone
+};
+
+enum eImageType {
+ itChannelLogo,
+ itSepLogo,
+ itSkinPart,
+ itMenuIcon,
+ itIcon,
+ itImage
+};
+
+enum eFloatType {
+ flNone,
+ flTopLeft,
+ flTopRight
+};
+
+enum eOverflowType {
+ otNone,
+ otWrap,
+ otCut
+};
+
+class cTemplateFunction {
+protected:
+ eFuncType type;
+ bool debug;
+ int containerX; //X of parent container
+ int containerY; //Y of parent container
+ int containerWidth; //width of parent container
+ int containerHeight; //height of parent container
+ int columnWidth; //if func is executed in a loop, width of loop column
+ int rowHeight; //if func is executed in a loop, height of loop row
+ cGlobals *globals; //globals
+ map< eParamType, string > nativeParameters; //native parameters directly from xml
+ map< eParamType, int > numericParameters; //sucessfully parsed numeric parameters
+ map< eParamType, string > numericDynamicParameters; //numeric parameters with dynamic tokens
+ bool parsedCompletely;
+ bool updated;
+ map< eParamType, tColor > colorParameters;
+ cConditionalParameter *condParam;
+ //drawimage parameters
+ string imgPath;
+ //drawtext parameters
+ string fontName;
+ vector<cTextToken> textTokens;
+ string parsedText;
+ int parsedTextWidth;
+ string cuttedText;
+ bool alreadyCutted;
+ //drawtextbox parameters
+ int textboxHeight;
+ //dynamic tokens
+ map < string, string > *stringTokens;
+ map < string, int > *intTokens;
+ //private functions
+ bool SetCondition(string cond);
+ bool SetNumericParameter(eParamType type, string value);
+ bool SetAlign(eParamType type, string value);
+ bool SetFont(eParamType type, string value);
+ bool SetImageType(eParamType type, string value);
+ bool SetColor(eParamType type, string value);
+ bool SetTextTokens(string value);
+ void ParseTextToken(string &value, size_t start, size_t end);
+ void ParseConditionalTextToken(string &value, size_t start, size_t end);
+ bool SetScrollMode(string value);
+ bool SetScrollSpeed(string value);
+ bool SetOrientation(string value);
+ bool SetFloating(string value);
+ bool SetOverflow(string value);
+ void ParseStringParameters(void);
+ void ParseNumericalParameters(void);
+ void CalculateAlign(int elementWidth, int elementHeight);
+ int CalculateTextBoxHeight(void);
+public:
+ cTemplateFunction(eFuncType type);
+ virtual ~cTemplateFunction(void);
+ //Setter Functions
+ void SetParameters(vector<pair<string, string> > params);
+ void SetParameter(eParamType type, string value);
+ void SetContainer(int x, int y, int w, int h);
+ void SetLoopContainer(int columnWidth, int rowHeight);
+ void SetWidthManually(string width);
+ void SetHeightManually(string height);
+ void SetXManually(int newX);
+ void SetYManually(int newY);
+ void SetMaxTextWidth(int maxWidth);
+ void SetTextboxHeight(int boxHeight);
+ void SetGlobals(cGlobals *globals) { this->globals = globals; };
+ void SetTranslatedText(string translation);
+ //PreCache Parameters
+ bool CalculateParameters(void);
+ void CompleteParameters(void);
+ //Set and Unset Dynamic Tokens from view
+ void SetStringTokens(map < string, string > *tok) { stringTokens = tok; };
+ void SetIntTokens(map < string, int > *tok) { intTokens = tok; };
+ void UnsetIntTokens(void) { intTokens = NULL; };
+ void UnsetStringTokens(void) { stringTokens = NULL; };
+ //Clear dynamically parameters
+ void ClearDynamicParameters(void);
+ //Parse parameters with dynamically set Tokens
+ bool ParseParameters(void);
+ //Getter Functions
+ eFuncType GetType(void) { return type; };
+ bool DoDebug(void) { return debug; };
+ string GetParameter(eParamType type);
+ int GetNumericParameter(eParamType type);
+ string GetText(bool cut = true);
+ string GetImagePath(void) { return imgPath; };
+ tColor GetColorParameter(eParamType type);
+ string GetFontName(void) { return fontName; };
+ string GetFuncName(void);
+ string GetParamName(eParamType pt);
+ //Dynamic width or height parameter
+ int GetWidth(bool cutted = true);
+ int GetHeight(void);
+ void GetNeededWidths(multimap<eParamType,string> *widths);
+ void GetNeededHeights(multimap<eParamType,string> *heights);
+ void GetNeededPosX(multimap<eParamType,string> *posXs);
+ void GetNeededPosY(multimap<eParamType,string> *posYs);
+ void SetWidth(eParamType type, string label, int funcWidth);
+ void SetHeight(eParamType type, string label, int funcHeight);
+ void SetX(eParamType type, string label, int funcX);
+ void SetY(eParamType type, string label, int funcY);
+ //Status Functions
+ bool ParsedCompletely(void) { return parsedCompletely; };
+ bool DoExecute(void);
+ bool Updated(void) { return updated; };
+ //Debug
+ void Debug(void);
+};
+
+#endif //__TEMPLATEFUNCTION_H \ No newline at end of file
diff --git a/libtemplate/templateloopfunction.c b/libtemplate/templateloopfunction.c
new file mode 100644
index 0000000..b0030d3
--- /dev/null
+++ b/libtemplate/templateloopfunction.c
@@ -0,0 +1,208 @@
+#include "templateloopfunction.h"
+#include "../libcore/helpers.h"
+
+using namespace std;
+
+// --- cTemplateFunction -------------------------------------------------------------
+
+cTemplateLoopFunction::cTemplateLoopFunction(void) : cTemplateFunction(ftLoop) {
+}
+
+cTemplateLoopFunction::~cTemplateLoopFunction(void) {
+}
+
+void cTemplateLoopFunction::InitIterator(void) {
+ funcIt = functions.begin();
+}
+
+void cTemplateLoopFunction::AddFunction(string name, vector<pair<string, string> > &params) {
+ eFuncType type = ftNone;
+
+ if (!name.compare("drawtext")) {
+ type = ftDrawText;
+ } else if (!name.compare("drawtextbox")) {
+ type = ftDrawTextBox;
+ } else if (!name.compare("drawimage")) {
+ type = ftDrawImage;
+ } else if (!name.compare("drawrectangle")) {
+ type = ftDrawRectangle;
+ } else if (!name.compare("drawellipse")) {
+ type = ftDrawEllipse;
+ }
+
+ if (type == ftNone) {
+ return;
+ }
+
+ cTemplateFunction *f = new cTemplateFunction(type);
+ f->SetParameters(params);
+ functions.push_back(f);
+}
+
+void cTemplateLoopFunction::CalculateLoopFuncParameters(void) {
+ int columnWidth = GetNumericParameter(ptColumnWidth);
+ int rowHeight = GetNumericParameter(ptRowHeight);
+ for (vector<cTemplateFunction*>::iterator func = functions.begin(); func != functions.end(); func++) {
+ (*func)->SetGlobals(globals);
+ (*func)->SetContainer(0, 0, containerWidth, containerHeight);
+ (*func)->SetLoopContainer(columnWidth, rowHeight);
+ (*func)->CalculateParameters();
+ (*func)->CompleteParameters();
+ }
+}
+
+cTemplateFunction *cTemplateLoopFunction::GetNextFunction(void) {
+ if (funcIt == functions.end())
+ return NULL;
+ cTemplateFunction *func = *funcIt;
+ funcIt++;
+ return func;
+}
+
+void cTemplateLoopFunction::ClearDynamicParameters(void) {
+ InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = GetNextFunction()) {
+ func->ClearDynamicParameters();
+ }
+}
+
+void cTemplateLoopFunction::ParseDynamicParameters(map <string,string> *tokens) {
+ if (!tokens)
+ return;
+ InitIterator();
+ cTemplateFunction *func = NULL;
+
+ map <string,int> intTokens;
+ for (map <string,string>::iterator it = tokens->begin(); it != tokens->end(); it++) {
+ if (isNumber(it->second))
+ intTokens.insert(pair<string, int>(it->first, atoi((it->second).c_str())));
+ }
+
+ bool completelyParsed = true;
+ while(func = GetNextFunction()) {
+ func->SetStringTokens(tokens);
+ func->SetIntTokens(&intTokens);
+ bool funcCompletelyParsed = func->ParseParameters();
+ if (!funcCompletelyParsed)
+ completelyParsed = false;
+ if (func->Updated())
+ func->CompleteParameters();
+ func->UnsetStringTokens();
+ func->UnsetIntTokens();
+ }
+ if (completelyParsed) {
+ return;
+ }
+
+ ReplaceWidthFunctions();
+ ReplaceHeightFunctions();
+}
+
+int cTemplateLoopFunction::GetLoopElementsWidth(void) {
+ int cW = GetNumericParameter(ptColumnWidth);
+ if (cW > 0) {
+ return cW;
+ }
+ InitIterator();
+ cTemplateFunction *func = NULL;
+ int maxWidth = 1;
+ while(func = GetNextFunction()) {
+ int funcWidth = func->GetWidth(true);
+ if (funcWidth > maxWidth)
+ maxWidth = funcWidth;
+ }
+ return maxWidth;
+}
+
+int cTemplateLoopFunction::GetLoopElementsHeight(void) {
+ int rH = GetNumericParameter(ptRowHeight);
+ if (rH > 0)
+ return rH;
+ InitIterator();
+ cTemplateFunction *func = NULL;
+ int maxHeight = 1;
+ while(func = GetNextFunction()) {
+ int funcY = func->GetNumericParameter(ptY);
+ int funcHeight = func->GetHeight();
+ int totalHeight = funcY + funcHeight;
+ if (totalHeight > maxHeight)
+ maxHeight = totalHeight;
+ }
+ return maxHeight;
+}
+
+void cTemplateLoopFunction::ReplaceWidthFunctions(void) {
+ InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = GetNextFunction()) {
+ if (func->ParsedCompletely()) {
+ continue;
+ }
+ multimap<eParamType,string> widths;
+ func->GetNeededWidths(&widths);
+ for (map<eParamType, string>::iterator names = widths.begin(); names !=widths.end(); names++) {
+ eParamType type = names->first;
+ string label = names->second;
+ int funcWidth = 0;
+ for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
+ cTemplateFunction *myFunc = *it;
+ string myFuncName = myFunc->GetParameter(ptName);
+ if (!myFuncName.compare(label)) {
+ funcWidth = myFunc->GetWidth();
+ func->SetWidth(type, label, funcWidth);
+ if (func->Updated()) {
+ func->CompleteParameters();
+ }
+ }
+ }
+ }
+ }
+}
+
+void cTemplateLoopFunction::ReplaceHeightFunctions(void) {
+ InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = GetNextFunction()) {
+ if (func->ParsedCompletely()) {
+ continue;
+ }
+ multimap<eParamType,string> heights;
+ func->GetNeededHeights(&heights);
+ for (map<eParamType, string>::iterator names = heights.begin(); names !=heights.end(); names++) {
+ eParamType type = names->first;
+ string label = names->second;
+ int funcHeight = 0;
+ for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
+ cTemplateFunction *myFunc = *it;
+ string myFuncName = myFunc->GetParameter(ptName);
+ if (!myFuncName.compare(label)) {
+ funcHeight = myFunc->GetHeight();
+ func->SetHeight(type, label, funcHeight);
+ if (func->Updated()) {
+ func->CompleteParameters();
+ }
+ }
+ }
+ }
+ }
+}
+
+bool cTemplateLoopFunction::Ready(void) {
+ bool isReady = true;
+ map< eParamType, string >::iterator hit = numericDynamicParameters.find(ptColumnWidth);
+ if (hit != numericDynamicParameters.end())
+ isReady = false;
+ hit = numericDynamicParameters.find(ptRowHeight);
+ if (hit != numericDynamicParameters.end())
+ isReady = false;
+ return isReady;
+}
+
+void cTemplateLoopFunction::Debug(void) {
+ cTemplateFunction::Debug();
+ esyslog("skindesigner: functions to be looped:");
+ for (vector<cTemplateFunction*>::iterator func = functions.begin(); func != functions.end(); func++) {
+ (*func)->Debug();
+ }
+} \ No newline at end of file
diff --git a/libtemplate/templateloopfunction.h b/libtemplate/templateloopfunction.h
new file mode 100644
index 0000000..5335279
--- /dev/null
+++ b/libtemplate/templateloopfunction.h
@@ -0,0 +1,33 @@
+#ifndef __TEMPLATELOOPFUNCTION_H
+#define __TEMPLATELOOPFUNCTION_H
+
+#include "templatefunction.h"
+
+using namespace std;
+
+// --- cTemplateLoopFunction -------------------------------------------------------------
+
+class cTemplateLoopFunction : public cTemplateFunction {
+private:
+ vector<cTemplateFunction*> functions;
+ vector<cTemplateFunction*>::iterator funcIt;
+ void ReplaceWidthFunctions(void);
+ void ReplaceHeightFunctions(void);
+public:
+ cTemplateLoopFunction(void);
+ virtual ~cTemplateLoopFunction(void);
+ void AddFunction(string name, vector<pair<string, string> > &params);
+ void CalculateLoopFuncParameters(void);
+ void InitIterator(void);
+ cTemplateFunction *GetNextFunction(void);
+ void ClearDynamicParameters(void);
+ void ParseDynamicParameters(map <string,string> *tokens);
+ int GetLoopElementsWidth(void);
+ int GetLoopElementsHeight(void);
+ int GetContainerWidth(void) { return containerWidth; };
+ int GetContainerHeight(void) { return containerHeight; };
+ bool Ready(void);
+ void Debug(void);
+};
+
+#endif //__TEMPLATELOOPFUNCTION_H
diff --git a/libtemplate/templatepixmap.c b/libtemplate/templatepixmap.c
new file mode 100644
index 0000000..8aaa4f3
--- /dev/null
+++ b/libtemplate/templatepixmap.c
@@ -0,0 +1,473 @@
+#include "templatepixmap.h"
+
+using namespace std;
+
+// --- cTemplatePixmap -------------------------------------------------------------
+
+cTemplatePixmap::cTemplatePixmap(void) {
+ parameters = NULL;
+ containerX = 0;
+ containerY = 0;
+ containerWidth = 0;
+ containerHeight = 0;
+ globals = NULL;
+ scrolling = false;
+}
+
+cTemplatePixmap::~cTemplatePixmap() {
+ for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
+ delete (*it);
+ }
+ if (parameters)
+ delete parameters;
+}
+
+void cTemplatePixmap::SetParameters(vector<pair<string, string> > &params) {
+ parameters = new cTemplateFunction(ftPixmap);
+ parameters->SetGlobals(globals);
+ parameters->SetParameters(params);
+}
+
+void cTemplatePixmap::SetContainer(int x, int y, int w, int h) {
+ containerX = x;
+ containerY = y;
+ containerWidth = w;
+ containerHeight = h;
+}
+
+void cTemplatePixmap::SetWidth(int width) {
+ cString pWidth = cString::sprintf("%d", width);
+ parameters->SetWidthManually(*pWidth);
+}
+
+void cTemplatePixmap::SetHeight(int height) {
+ cString pHeight = cString::sprintf("%d", height);
+ parameters->SetHeightManually(*pHeight);
+}
+
+void cTemplatePixmap::SetX(int x) {
+ parameters->SetXManually(x);
+}
+
+void cTemplatePixmap::SetY(int y) {
+ parameters->SetYManually(y);
+}
+
+void cTemplatePixmap::ClearDynamicParameters(void) {
+ parameters->ClearDynamicParameters();
+}
+
+void cTemplatePixmap::ParseDynamicParameters(map <string,int> *intTokens, bool initFuncs) {
+ parameters->ClearDynamicParameters();
+ parameters->SetIntTokens(intTokens);
+ parameters->ParseParameters();
+ parameters->UnsetIntTokens();
+
+ if (!DoExecute()) {
+ parameters->ClearDynamicParameters();
+ return;
+ }
+
+ if (!initFuncs || !Ready())
+ return;
+
+ int x = parameters->GetNumericParameter(ptX);
+ int y = parameters->GetNumericParameter(ptY);
+ int width = parameters->GetNumericParameter(ptWidth);
+ int height = parameters->GetNumericParameter(ptHeight);
+
+ for (vector<cTemplateFunction*>::iterator func = functions.begin(); func != functions.end(); func++) {
+ (*func)->SetContainer(x, y, width, height);
+ (*func)->CalculateParameters();
+ (*func)->CompleteParameters();
+ if ((*func)->GetType() == ftLoop) {
+ cTemplateLoopFunction *loopFunc = dynamic_cast<cTemplateLoopFunction*>(*func);
+ if (!loopFunc->Ready()) {
+ loopFunc->SetIntTokens(intTokens);
+ loopFunc->ParseParameters();
+ loopFunc->UnsetIntTokens();
+ }
+ loopFunc->CalculateLoopFuncParameters();
+ }
+ }
+}
+
+void cTemplatePixmap::AddFunction(string name, vector<pair<string, string> > &params) {
+ eFuncType type = ftNone;
+
+ if (!name.compare("fill")) {
+ type = ftFill;
+ } else if (!name.compare("drawtext")) {
+ type = ftDrawText;
+ } else if (!name.compare("drawtextbox")) {
+ type = ftDrawTextBox;
+ } else if (!name.compare("drawimage")) {
+ type = ftDrawImage;
+ } else if (!name.compare("drawrectangle")) {
+ type = ftDrawRectangle;
+ } else if (!name.compare("drawellipse")) {
+ type = ftDrawEllipse;
+ }
+
+ if (type == ftNone) {
+ return;
+ }
+
+ cTemplateFunction *f = new cTemplateFunction(type);
+ f->SetParameters(params);
+ functions.push_back(f);
+}
+
+void cTemplatePixmap::AddLoopFunction(cTemplateLoopFunction *lf) {
+ functions.push_back(lf);
+}
+
+
+bool cTemplatePixmap::CalculateParameters(void) {
+ bool paramsValid = true;
+ //Calculate Pixmap Size
+ parameters->SetContainer(containerX, containerY, containerWidth, containerHeight);
+ parameters->SetGlobals(globals);
+ paramsValid = parameters->CalculateParameters();
+
+ int pixWidth = parameters->GetNumericParameter(ptWidth);
+ int pixHeight = parameters->GetNumericParameter(ptHeight);
+
+ for (vector<cTemplateFunction*>::iterator func = functions.begin(); func != functions.end(); func++) {
+ (*func)->SetGlobals(globals);
+ if (!Ready())
+ continue;
+ (*func)->SetContainer(0, 0, pixWidth, pixHeight);
+ paramsValid = (*func)->CalculateParameters();
+ (*func)->CompleteParameters();
+ if ((*func)->GetType() == ftLoop) {
+ cTemplateLoopFunction *loopFunc = dynamic_cast<cTemplateLoopFunction*>(*func);
+ loopFunc->CalculateLoopFuncParameters();
+ }
+ }
+
+ return paramsValid;
+}
+
+void cTemplatePixmap::ClearDynamicFunctionParameters(void) {
+ InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = GetNextFunction()) {
+ func->ClearDynamicParameters();
+ }
+}
+
+void cTemplatePixmap::ParseDynamicFunctionParameters(map <string,string> *stringTokens, map <string,int> *intTokens) {
+ InitIterator();
+ cTemplateFunction *func = NULL;
+ bool completelyParsed = true;
+ bool updated = false;
+ while(func = GetNextFunction()) {
+ func->SetStringTokens(stringTokens);
+ func->SetIntTokens(intTokens);
+ bool funcCompletelyParsed = func->ParseParameters();
+ if (!funcCompletelyParsed)
+ completelyParsed = false;
+ if (func->Updated())
+ func->CompleteParameters();
+ func->UnsetIntTokens();
+ func->UnsetStringTokens();
+ }
+
+ if (completelyParsed) {
+ return;
+ }
+
+ ReplaceWidthFunctions();
+ ReplaceHeightFunctions();
+ ReplacePosXFunctions();
+ ReplacePosYFunctions();
+}
+
+bool cTemplatePixmap::CalculateDrawPortSize(cSize &size, map < string, vector< map< string, string > > > *loopTokens) {
+ int pixWidth = parameters->GetNumericParameter(ptWidth);
+ int pixHeight = parameters->GetNumericParameter(ptHeight);
+ int orientation = parameters->GetNumericParameter(ptOrientation);
+ if (orientation < 0)
+ orientation = orVertical;
+ if (orientation == orHorizontal) {
+ //get function which determinates drawport width
+ cTemplateFunction *scrollFunc = GetScrollFunction();
+ if (!scrollFunc)
+ return false;
+ int drawportWidth = scrollFunc->GetWidth(false) + scrollFunc->GetNumericParameter(ptX) + 10;
+ if (drawportWidth > pixWidth) {
+ size.SetWidth(drawportWidth);
+ size.SetHeight(pixHeight);
+ return true;
+ }
+ } else if (orientation == orVertical) {
+ //check "last" element height
+ InitIterator();
+ cTemplateFunction *f = NULL;
+ int drawportHeight = 1;
+ while (f = GetNextFunction()) {
+ if (f->GetType() == ftLoop) {
+ cTemplateLoopFunction *loopFunc = dynamic_cast<cTemplateLoopFunction*>(f);
+ //get number of loop tokens
+ string loopTokenName = loopFunc->GetParameter(ptName);
+ int numLoopTokens = 0;
+ map < string, vector< map< string, string > > >::iterator hit = loopTokens->find(loopTokenName);
+ if (hit != loopTokens->end()) {
+ vector< map<string,string> > loopToken = hit->second;
+ numLoopTokens = loopToken.size();
+ //parse first loop token element to get correct height
+ vector< map<string,string> >::iterator firstLoopToken = loopToken.begin();
+ loopFunc->ClearDynamicParameters();
+ loopFunc->ParseDynamicParameters(&(*firstLoopToken));
+ }
+ int orientation = loopFunc->GetNumericParameter(ptOrientation);
+ int yFunc = loopFunc->GetNumericParameter(ptY);
+ int heightFunc = loopFunc->GetLoopElementsHeight();
+ if (loopTokens && orientation == orVertical) {
+ //height is height of loop elements times num loop elements
+ heightFunc = heightFunc * numLoopTokens;
+ } else if (loopTokens && orientation == orHorizontal) {
+ int overflow = loopFunc->GetNumericParameter(ptOverflow);
+ if (overflow == otCut) {
+ //do nothing, height is only height of one line
+ } else if (overflow == otWrap) {
+ int widthFunc = loopFunc->GetLoopElementsWidth();
+ if (widthFunc <= 0)
+ continue;
+ int loopWidth = loopFunc->GetNumericParameter(ptWidth);
+ if (loopWidth <= 0)
+ loopWidth = loopFunc->GetContainerWidth();
+ int elementsPerRow = loopWidth / widthFunc;
+ int rest = loopWidth % widthFunc;
+ if (rest > 0)
+ elementsPerRow++;
+ if (elementsPerRow <= 0)
+ continue;
+ int lines = numLoopTokens / elementsPerRow;
+ rest = numLoopTokens % elementsPerRow;
+ if (rest > 0)
+ lines++;
+ heightFunc = heightFunc * lines;
+ }
+ }
+ int neededHeight = heightFunc + yFunc;
+ if (neededHeight > drawportHeight)
+ drawportHeight = neededHeight;
+ } else {
+ int yFunc = f->GetNumericParameter(ptY);
+ int heightFunc = f->GetHeight();
+ int neededHeight = heightFunc + yFunc;
+ if (neededHeight > drawportHeight)
+ drawportHeight = neededHeight;
+ }
+ }
+ if (drawportHeight > pixHeight) {
+ size.SetWidth(pixWidth);
+ size.SetHeight(drawportHeight);
+ return true;
+ }
+ }
+ size.SetWidth(0);
+ size.SetHeight(0);
+ return false;
+}
+
+void cTemplatePixmap::SetScrollingTextWidth(void) {
+ int orientation = parameters->GetNumericParameter(ptOrientation);
+ if (orientation != orHorizontal)
+ return;
+ int pixWidth = parameters->GetNumericParameter(ptWidth);
+ InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = GetNextFunction()) {
+ if (func->GetType() == ftDrawText) {
+ int offset = func->GetNumericParameter(ptX);
+ func->SetMaxTextWidth(pixWidth - offset);
+ }
+ }
+}
+
+
+cTemplateFunction *cTemplatePixmap::GetScrollFunction(void) {
+ string scrollElement = parameters->GetParameter(ptScrollElement);
+ if (scrollElement.size() == 0)
+ return NULL;
+ InitIterator();
+ cTemplateFunction *f = NULL;
+ bool foundElement = false;
+ while (f = GetNextFunction()) {
+ string funcName = f->GetParameter(ptName);
+ if (!funcName.compare(scrollElement)) {
+ return f;
+ }
+ }
+ return NULL;
+}
+
+cRect cTemplatePixmap::GetPixmapSize(void) {
+ cRect size;
+ size.SetX(GetNumericParameter(ptX));
+ size.SetY(GetNumericParameter(ptY));
+ size.SetWidth(GetNumericParameter(ptWidth));
+ size.SetHeight(GetNumericParameter(ptHeight));
+ return size;
+}
+
+int cTemplatePixmap::GetNumericParameter(eParamType type) {
+ if (!parameters)
+ return -1;
+ return parameters->GetNumericParameter(type);
+}
+
+void cTemplatePixmap::InitIterator(void) {
+ funcIt = functions.begin();
+}
+
+cTemplateFunction *cTemplatePixmap::GetNextFunction(void) {
+ if (funcIt == functions.end())
+ return NULL;
+ cTemplateFunction *func = *funcIt;
+ funcIt++;
+ return func;
+}
+
+bool cTemplatePixmap::Ready(void) {
+ int myX = parameters->GetNumericParameter(ptX);
+ if (myX < 0)
+ return false;
+ int myY = parameters->GetNumericParameter(ptY);
+ if (myY < 0)
+ return false;
+ int myWidth = parameters->GetNumericParameter(ptWidth);
+ if (myWidth < 1)
+ return false;
+ int myHeight = parameters->GetNumericParameter(ptHeight);
+ if (myHeight < 1)
+ return false;
+ return true;
+}
+
+void cTemplatePixmap::ReplaceWidthFunctions(void) {
+ InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = GetNextFunction()) {
+ if (func->ParsedCompletely()) {
+ continue;
+ }
+ multimap<eParamType,string> widths;
+ func->GetNeededWidths(&widths);
+ for (map<eParamType, string>::iterator names = widths.begin(); names !=widths.end(); names++) {
+ eParamType type = names->first;
+ string label = names->second;
+ int funcWidth = 0;
+ for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
+ cTemplateFunction *myFunc = *it;
+ string myFuncName = myFunc->GetParameter(ptName);
+ if (!myFuncName.compare(label)) {
+ funcWidth = myFunc->GetWidth();
+ func->SetWidth(type, label, funcWidth);
+ if (func->Updated()) {
+ func->CompleteParameters();
+ }
+ }
+ }
+ }
+ }
+}
+
+void cTemplatePixmap::ReplaceHeightFunctions(void) {
+ InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = GetNextFunction()) {
+ if (func->ParsedCompletely()) {
+ continue;
+ }
+ multimap<eParamType,string> heights;
+ func->GetNeededHeights(&heights);
+ for (map<eParamType, string>::iterator names = heights.begin(); names !=heights.end(); names++) {
+ eParamType type = names->first;
+ string label = names->second;
+ int funcHeight = 0;
+ for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
+ cTemplateFunction *myFunc = *it;
+ string myFuncName = myFunc->GetParameter(ptName);
+ if (!myFuncName.compare(label)) {
+ funcHeight = myFunc->GetHeight();
+ func->SetHeight(type, label, funcHeight);
+ if (func->Updated()) {
+ func->CompleteParameters();
+ }
+ }
+ }
+ }
+ }
+}
+
+void cTemplatePixmap::ReplacePosXFunctions(void) {
+ InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = GetNextFunction()) {
+ if (func->ParsedCompletely()) {
+ continue;
+ }
+ multimap<eParamType,string> posXs;
+ func->GetNeededPosX(&posXs);
+ for (map<eParamType, string>::iterator names = posXs.begin(); names !=posXs.end(); names++) {
+ eParamType type = names->first;
+ string label = names->second;
+ int funcX = 0;
+ for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
+ cTemplateFunction *myFunc = *it;
+ string myFuncName = myFunc->GetParameter(ptName);
+ if (!myFuncName.compare(label)) {
+ funcX = myFunc->GetNumericParameter(ptX);
+ if (funcX > -1) {
+ func->SetX(type, label, funcX);
+ if (func->Updated()) {
+ func->CompleteParameters();
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void cTemplatePixmap::ReplacePosYFunctions(void) {
+ InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = GetNextFunction()) {
+ if (func->ParsedCompletely()) {
+ continue;
+ }
+ multimap<eParamType,string> posYs;
+ func->GetNeededPosY(&posYs);
+ for (map<eParamType, string>::iterator names = posYs.begin(); names !=posYs.end(); names++) {
+ eParamType type = names->first;
+ string label = names->second;
+ int funcY = 0;
+ for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
+ cTemplateFunction *myFunc = *it;
+ string myFuncName = myFunc->GetParameter(ptName);
+ if (!myFuncName.compare(label)) {
+ funcY = myFunc->GetNumericParameter(ptY);
+ if (funcY > -1) {
+ func->SetY(type, label, funcY);
+ if (func->Updated()) {
+ func->CompleteParameters();
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void cTemplatePixmap::Debug(void) {
+ esyslog("skindesigner: pixmap container size x: %d, y: %d, width: %d, height %d", containerX, containerY, containerWidth, containerHeight);
+ parameters->Debug();
+ for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
+ (*it)->Debug();
+ }
+}
diff --git a/libtemplate/templatepixmap.h b/libtemplate/templatepixmap.h
new file mode 100644
index 0000000..6cf3bd5
--- /dev/null
+++ b/libtemplate/templatepixmap.h
@@ -0,0 +1,82 @@
+#ifndef __TEMPLATEPIXMAP_H
+#define __TEMPLATEPIXMAP_H
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <sstream>
+
+#include "globals.h"
+#include "templateloopfunction.h"
+
+using namespace std;
+
+// --- cTemplatePixmap -------------------------------------------------------------
+
+class cTemplatePixmap {
+protected:
+ bool scrolling;
+ cTemplateFunction *parameters;
+ vector<cTemplateFunction*> functions;
+ vector<cTemplateFunction*>::iterator funcIt;
+ int containerX;
+ int containerY;
+ int containerWidth;
+ int containerHeight;
+ cGlobals *globals;
+ //functions replacing {width(label)} and {height(label)} tokens
+ void ReplaceWidthFunctions(void);
+ void ReplaceHeightFunctions(void);
+ //functions replacing {posx(label)} and {posy(label)} tokens
+ void ReplacePosXFunctions(void);
+ void ReplacePosYFunctions(void);
+ //Get Scrolling Function
+ cTemplateFunction *GetScrollFunction(void);
+public:
+ cTemplatePixmap(void);
+ virtual ~cTemplatePixmap(void);
+ //Setter Functions
+ void SetScrolling(void) { scrolling = true; };
+ void SetParameters(vector<pair<string, string> > &params);
+ void SetWidth(int width);
+ void SetHeight(int height);
+ void SetX(int x);
+ void SetY(int y);
+ void SetContainer(int x, int y, int w, int h);
+ void SetGlobals(cGlobals *globals) { this->globals = globals; };
+ void AddFunction(string name, vector<pair<string, string> > &params);
+ void AddLoopFunction(cTemplateLoopFunction *lf);
+ //PreCache Parameters
+ bool CalculateParameters(void);
+ //clear dynamically set function parameters
+ void ClearDynamicFunctionParameters(void);
+ //Clear dynamically set pixmap parameters
+ void ClearDynamicParameters(void);
+ //Parse pixmap parameters with dynamically set Tokens
+ void ParseDynamicParameters(map <string,int> *intTokens, bool initFuncs);
+ //Parse all function parameters with dynamically set Tokens
+ void ParseDynamicFunctionParameters(map <string,string> *stringTokens, map <string,int> *intTokens);
+ //Calculate size of drawport in case area scrolls
+ bool CalculateDrawPortSize(cSize &size, map < string, vector< map< string, string > > > *loopTokens = NULL);
+ //Set max width for text in scrollarea
+ void SetScrollingTextWidth(void);
+ //Getter Functions
+ cRect GetPixmapSize(void);
+ int GetNumericParameter(eParamType type);
+ bool Scrolling(void) { return scrolling; };
+ bool DoExecute(void) { return parameters->DoExecute(); };
+ bool DoDebug(void) { return parameters->DoDebug(); };
+ bool Ready(void);
+ //Traverse Functions
+ void InitIterator(void);
+ cTemplateFunction *GetNextFunction(void);
+ //Debug
+ void Debug(void);
+};
+
+#endif //__TEMPLATEPIXMAP_H \ No newline at end of file
diff --git a/libtemplate/templateview.c b/libtemplate/templateview.c
new file mode 100644
index 0000000..abaedc8
--- /dev/null
+++ b/libtemplate/templateview.c
@@ -0,0 +1,1567 @@
+#include "templateview.h"
+
+// --- cTemplateView -------------------------------------------------------------
+
+cTemplateView::cTemplateView(void) {
+ globals = NULL;
+ parameters = NULL;
+ containerX = 0;
+ containerY = 0;
+ containerWidth = 0;
+ containerHeight = 0;
+ SetFunctionDefinitions();
+}
+
+cTemplateView::~cTemplateView() {
+
+ for (map < eViewElement, cTemplateViewElement* >::iterator it = viewElements.begin(); it != viewElements.end(); it++) {
+ delete it->second;
+ }
+
+ for (map < eViewList, cTemplateViewList* >::iterator it = viewLists.begin(); it != viewLists.end(); it++) {
+ delete it->second;
+ }
+
+ for (vector < cTemplateViewTab* >::iterator it = viewTabs.begin(); it != viewTabs.end(); it++) {
+ delete *it;
+ }
+
+ if (parameters)
+ delete parameters;
+
+}
+
+/*******************************************************************
+* Public Functions
+*******************************************************************/
+
+void cTemplateView::SetParameters(vector<pair<string, string> > &params) {
+ parameters = new cTemplateFunction(ftView);
+ parameters->SetGlobals(globals);
+ parameters->SetParameters(params);
+}
+
+void cTemplateView::SetContainer(int x, int y, int width, int height) {
+ containerX = x;
+ containerY = y;
+ containerWidth = width;
+ containerHeight = height;
+}
+
+cTemplateViewElement *cTemplateView::GetViewElement(eViewElement ve) {
+ map < eViewElement, cTemplateViewElement* >::iterator hit = viewElements.find(ve);
+ if (hit == viewElements.end())
+ return NULL;
+ return hit->second;
+}
+
+void cTemplateView::InitViewElementIterator(void) {
+ veIt = viewElements.begin();
+}
+
+cTemplateViewElement *cTemplateView::GetNextViewElement(void) {
+ if (veIt == viewElements.end())
+ return NULL;
+ cTemplateViewElement *viewElement = veIt->second;
+ veIt++;
+ return viewElement;
+}
+
+cTemplateViewList *cTemplateView::GetViewList(eViewList vl) {
+ map < eViewList, cTemplateViewList* >::iterator hit = viewLists.find(vl);
+ if (hit == viewLists.end())
+ return NULL;
+ return hit->second;
+}
+
+void cTemplateView::InitViewListIterator(void) {
+ vlIt = viewLists.begin();
+}
+
+cTemplateViewList *cTemplateView::GetNextViewList(void) {
+ if (vlIt == viewLists.end())
+ return NULL;
+ cTemplateViewList *viewList = vlIt->second;
+ vlIt++;
+ return viewList;
+}
+
+cTemplateView *cTemplateView::GetSubView(eSubView sv) {
+ map < eSubView, cTemplateView* >::iterator hit = subViews.find(sv);
+ if (hit == subViews.end())
+ return NULL;
+ return hit->second;
+}
+
+void cTemplateView::InitViewTabIterator(void) {
+ vtIt = viewTabs.begin();
+}
+
+cTemplateViewTab *cTemplateView::GetNextViewTab(void) {
+ if (vtIt == viewTabs.end()) {
+ return NULL;
+ }
+ cTemplateViewTab *tab = *vtIt;
+ vtIt++;
+ return tab;
+}
+
+void cTemplateView::InitSubViewIterator(void) {
+ svIt = subViews.begin();
+}
+
+cTemplateView *cTemplateView::GetNextSubView(void) {
+ if (svIt == subViews.end())
+ return NULL;
+ cTemplateView *subView = svIt->second;
+ svIt++;
+ return subView;
+}
+
+int cTemplateView::GetNumericParameter(eParamType type) {
+ if (!parameters)
+ return 0;
+ return parameters->GetNumericParameter(type);
+}
+
+cRect cTemplateView::GetOsdSize(void) {
+ cRect osdSize;
+ if (!parameters) {
+ return osdSize;
+ }
+ osdSize.SetX(parameters->GetNumericParameter(ptX));
+ osdSize.SetY(parameters->GetNumericParameter(ptY));
+ osdSize.SetWidth(parameters->GetNumericParameter(ptWidth));
+ osdSize.SetHeight(parameters->GetNumericParameter(ptHeight));
+ return osdSize;
+}
+
+int cTemplateView::GetNumPixmaps(void) {
+ int numPixmaps = 0;
+ for (map < eViewElement, cTemplateViewElement* >::iterator it = viewElements.begin(); it != viewElements.end(); it++) {
+ cTemplateViewElement *viewElement = it->second;
+ numPixmaps += viewElement->GetNumPixmaps();
+ }
+ return numPixmaps;
+}
+
+int cTemplateView::GetNumPixmapsViewElement(eViewElement ve) {
+ map < eViewElement, cTemplateViewElement* >::iterator hit = viewElements.find(ve);
+ if (hit == viewElements.end())
+ return 0;
+ cTemplateViewElement *viewElement = hit->second;
+ return viewElement->GetNumPixmaps();
+}
+
+int cTemplateView::GetNumListViewMenuItems(void) {
+ int numElements = 0;
+ cTemplateViewList *menuList = GetViewList(vlMenuItem);
+ if (!menuList)
+ return numElements;
+ return menuList->GetNumericParameter(ptNumElements);
+}
+
+bool cTemplateView::GetScalingWindow(cRect &scalingWindow) {
+ if (!parameters)
+ return false;
+ bool doScale = false;
+ int scaleX = parameters->GetNumericParameter(ptScaleTvX);
+ int scaleY = parameters->GetNumericParameter(ptScaleTvY);
+ int scaleWidth = parameters->GetNumericParameter(ptScaleTvWidth);
+ int scaleHeight = parameters->GetNumericParameter(ptScaleTvHeight);
+ if (scaleX > -1 && scaleY > -1 && scaleWidth > -1 && scaleHeight > -1) {
+ cRect suggestedScaleWindow(scaleX, scaleY, scaleWidth, scaleHeight);
+ scalingWindow = cDevice::PrimaryDevice()->CanScaleVideo(suggestedScaleWindow);
+ doScale = true;
+ } else {
+ scalingWindow = cDevice::PrimaryDevice()->CanScaleVideo(cRect::Null);
+ }
+ return doScale;
+}
+
+bool cTemplateView::ValidViewElement(const char *viewElement) {
+ set<string>::iterator hit = viewElementsAllowed.find(viewElement);
+ if (hit == viewElementsAllowed.end())
+ return false;
+ return true;
+}
+
+bool cTemplateView::ValidSubView(const char *subView) {
+ set<string>::iterator hit = subViewsAllowed.find(subView);
+ if (hit == subViewsAllowed.end())
+ return false;
+ return true;
+}
+
+bool cTemplateView::ValidViewList(const char *viewList) {
+ set<string>::iterator hit = viewListsAllowed.find(viewList);
+ if (hit == viewListsAllowed.end())
+ return false;
+ return true;
+}
+
+bool cTemplateView::ValidFunction(const char *func) {
+ map < string, set < string > >::iterator hit = funcsAllowed.find(func);
+ if (hit == funcsAllowed.end())
+ return false;
+ return true;
+}
+
+bool cTemplateView::ValidAttribute(const char *func, const char *att) {
+ map < string, set < string > >::iterator hit = funcsAllowed.find(func);
+ if (hit == funcsAllowed.end())
+ return false;
+
+ set<string>::iterator hitAtt = (hit->second).find(att);
+ if (hitAtt == (hit->second).end())
+ return false;
+
+ return true;
+}
+
+void cTemplateView::Translate(void) {
+ //Translate ViewElements
+ InitViewElementIterator();
+ cTemplateViewElement *viewElement = NULL;
+ while(viewElement = GetNextViewElement()) {
+ viewElement->InitIterator();
+ cTemplatePixmap *pix = NULL;
+ while(pix = viewElement->GetNextPixmap()) {
+ pix->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = pix->GetNextFunction()) {
+ if (func->GetType() == ftDrawText || func->GetType() == ftDrawTextBox) {
+ string text = func->GetParameter(ptText);
+ string translation;
+ bool translated = globals->Translate(text, translation);
+ if (translated) {
+ func->SetTranslatedText(translation);
+ }
+ }
+ }
+ }
+ }
+ //Translate viewLists
+ InitViewListIterator();
+ cTemplateViewList *viewList = NULL;
+ while(viewList = GetNextViewList()) {
+ viewList->InitIterator();
+ cTemplatePixmap *pix = NULL;
+ while(pix = viewList->GetNextPixmap()) {
+ pix->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = pix->GetNextFunction()) {
+ if (func->GetType() == ftDrawText || func->GetType() == ftDrawTextBox) {
+ string text = func->GetParameter(ptText);
+ string translation;
+ bool translated = globals->Translate(text, translation);
+ if (translated) {
+ func->SetTranslatedText(translation);
+ }
+ }
+ }
+ }
+ cTemplateViewElement *listElement = viewList->GetListElement();
+ listElement->InitIterator();
+ while(pix = listElement->GetNextPixmap()) {
+ pix->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = pix->GetNextFunction()) {
+ if (func->GetType() == ftDrawText || func->GetType() == ftDrawTextBox) {
+ string text = func->GetParameter(ptText);
+ string translation;
+ bool translated = globals->Translate(text, translation);
+ if (translated) {
+ func->SetTranslatedText(translation);
+ }
+ }
+ }
+ }
+
+ cTemplateViewElement *listElementCurrent = viewList->GetListElementCurrent();
+ if (listElementCurrent) {
+ listElementCurrent->InitIterator();
+ while(pix = listElementCurrent->GetNextPixmap()) {
+ pix->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = pix->GetNextFunction()) {
+ if (func->GetType() == ftDrawText || func->GetType() == ftDrawTextBox) {
+ string text = func->GetParameter(ptText);
+ string translation;
+ bool translated = globals->Translate(text, translation);
+ if (translated) {
+ func->SetTranslatedText(translation);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //Translate viewTabs
+ InitViewTabIterator();
+ cTemplateViewTab *viewTab = NULL;
+ while(viewTab = GetNextViewTab()) {
+ string tabName = viewTab->GetName();
+ string tabTrans;
+ bool translated = globals->Translate(tabName, tabTrans);
+ if (translated) {
+ viewTab->SetName(tabTrans);
+ }
+ viewTab->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = viewTab->GetNextFunction()) {
+ if (func->GetType() == ftDrawText || func->GetType() == ftDrawTextBox) {
+ string text = func->GetParameter(ptText);
+ string translation;
+ translated = globals->Translate(text, translation);
+ if (translated) {
+ func->SetTranslatedText(translation);
+ }
+ }
+ }
+ }
+
+ //Translate Subviews
+ InitSubViewIterator();
+ cTemplateView *subView = NULL;
+ while(subView = GetNextSubView()) {
+ subView->Translate();
+ }
+}
+
+void cTemplateView::PreCache(bool isSubview) {
+
+ if (!isSubview) {
+ int osdW = cOsd::OsdWidth();
+ int osdH = cOsd::OsdHeight();
+ parameters->SetContainer(0, 0, osdW, osdH);
+ } else {
+ parameters->SetContainer(containerX, containerY, containerWidth, containerHeight);
+ }
+ //Calculate OSD Size
+ parameters->CalculateParameters();
+
+ int osdX = parameters->GetNumericParameter(ptX);
+ int osdY = parameters->GetNumericParameter(ptY);
+ int osdWidth = parameters->GetNumericParameter(ptWidth);
+ int osdHeight = parameters->GetNumericParameter(ptHeight);
+ int pixOffset = 0;
+
+ //Cache ViewElements
+ for (map < eViewElement, cTemplateViewElement* >::iterator it = viewElements.begin(); it != viewElements.end(); it++) {
+ cTemplateViewElement *viewElement = it->second;
+ viewElement->SetGlobals(globals);
+ viewElement->SetContainer(0, 0, osdWidth, osdHeight);
+ viewElement->CalculatePixmapParameters();
+ viewElement->SetPixOffset(pixOffset);
+ pixOffset += viewElement->GetNumPixmaps();
+ }
+
+ //Cache ViewLists
+ for (map < eViewList, cTemplateViewList* >::iterator it = viewLists.begin(); it != viewLists.end(); it++) {
+ cTemplateViewList *viewList = it->second;
+ viewList->SetGlobals(globals);
+ viewList->SetContainer(0, 0, osdWidth, osdHeight);
+ viewList->CalculateListParameters();
+ }
+
+ //Cache ViewTabs
+ for (vector<cTemplateViewTab*>::iterator tab = viewTabs.begin(); tab != viewTabs.end(); tab++) {
+ (*tab)->SetContainer(containerX, containerY, containerWidth, containerHeight);
+ (*tab)->SetGlobals(globals);
+ (*tab)->CalculateParameters();
+ }
+
+ //Cache Subviews
+ for (map < eSubView, cTemplateView* >::iterator it = subViews.begin(); it != subViews.end(); it++) {
+ cTemplateView *subView = it->second;
+ subView->SetContainer(0, 0, osdWidth, osdHeight);
+ subView->PreCache(true);
+ }
+
+}
+
+void cTemplateView::Debug(void) {
+
+ esyslog("skindesigner: TemplateView %s", viewName.c_str());;
+
+ parameters->Debug();
+
+ for (map < eViewElement, cTemplateViewElement* >::iterator it = viewElements.begin(); it != viewElements.end(); it++) {
+ esyslog("skindesigner: ++++++++ ViewElement: %s", GetViewElementName(it->first).c_str());
+ cTemplateViewElement *viewElement = it->second;
+ viewElement->Debug();
+ }
+
+ for (map < eViewList, cTemplateViewList* >::iterator it = viewLists.begin(); it != viewLists.end(); it++) {
+ esyslog("skindesigner: ++++++++ ViewList: %s", GetViewListName(it->first).c_str());
+ cTemplateViewList *viewList = it->second;
+ viewList->Debug();
+ }
+
+ for (vector<cTemplateViewTab*>::iterator tab = viewTabs.begin(); tab != viewTabs.end(); tab++) {
+ esyslog("skindesigner: ++++++++ ViewTab");
+ (*tab)->Debug();
+ }
+
+ for (map < eSubView, cTemplateView* >::iterator it = subViews.begin(); it!= subViews.end(); it++) {
+ esyslog("skindesigner: ++++++++ SubView: %s", GetSubViewName(it->first).c_str());
+ cTemplateView *subView = it->second;
+ subView->Debug();
+ }
+
+}
+
+
+void cTemplateView::SetFunctionDefinitions(void) {
+
+ string name = "area";
+ set<string> attributes;
+ attributes.insert("debug");
+ attributes.insert("condition");
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("layer");
+ attributes.insert("transparency");
+ funcsAllowed.insert(pair< string, set<string> >(name, attributes));
+
+ name = "areascroll";
+ attributes.clear();
+ attributes.insert("debug");
+ attributes.insert("orientation");
+ attributes.insert("delay");
+ attributes.insert("mode");
+ attributes.insert("scrollspeed");
+ attributes.insert("condition");
+ attributes.insert("scrollelement");
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("layer");
+ attributes.insert("transparency");
+ funcsAllowed.insert(pair< string, set<string> >(name, attributes));
+
+ name = "loop";
+ attributes.clear();
+ attributes.insert("debug");
+ attributes.insert("name");
+ attributes.insert("orientation");
+ attributes.insert("condition");
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("columnwidth");
+ attributes.insert("rowheight");
+ attributes.insert("overflow");
+ attributes.insert("maxitems");
+ funcsAllowed.insert(pair< string, set<string> >(name, attributes));
+
+ name = "fill";
+ attributes.clear();
+ attributes.insert("debug");
+ attributes.insert("condition");
+ attributes.insert("color");
+ funcsAllowed.insert(pair< string, set<string> >(name, attributes));
+
+ name = "drawtext";
+ attributes.clear();
+ attributes.insert("debug");
+ attributes.insert("condition");
+ attributes.insert("name");
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("align");
+ attributes.insert("valign");
+ attributes.insert("font");
+ attributes.insert("fontsize");
+ attributes.insert("color");
+ attributes.insert("text");
+ funcsAllowed.insert(pair< string, set<string> >(name, attributes));
+
+ name = "drawtextbox";
+ attributes.clear();
+ attributes.insert("debug");
+ attributes.insert("condition");
+ attributes.insert("name");
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("align");
+ attributes.insert("maxlines");
+ attributes.insert("font");
+ attributes.insert("fontsize");
+ attributes.insert("color");
+ attributes.insert("text");
+ attributes.insert("float");
+ attributes.insert("floatwidth");
+ attributes.insert("floatheight");
+ funcsAllowed.insert(pair< string, set<string> >(name, attributes));
+
+ name = "drawimage";
+ attributes.clear();
+ attributes.insert("debug");
+ attributes.insert("condition");
+ attributes.insert("name");
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("align");
+ attributes.insert("valign");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("imagetype");
+ attributes.insert("path");
+ attributes.insert("align");
+ attributes.insert("valign");
+ attributes.insert("cache");
+ funcsAllowed.insert(pair< string, set<string> >(name, attributes));
+
+ name = "drawrectangle";
+ attributes.clear();
+ attributes.insert("debug");
+ attributes.insert("condition");
+ attributes.insert("name");
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("align");
+ attributes.insert("valign");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("color");
+ funcsAllowed.insert(pair< string, set<string> >(name, attributes));
+
+ name = "drawellipse";
+ attributes.clear();
+ attributes.insert("debug");
+ attributes.insert("condition");
+ attributes.insert("name");
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("align");
+ attributes.insert("valign");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("color");
+ attributes.insert("quadrant");
+ funcsAllowed.insert(pair< string, set<string> >(name, attributes));
+
+}
+
+/************************************************************************************
+* cTemplateViewChannel
+************************************************************************************/
+
+cTemplateViewChannel::cTemplateViewChannel(void) {
+
+ viewName = "displaychannel";
+ //definition of allowed parameters for class itself
+ set<string> attributes;
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(viewName, attributes));
+
+ SetViewElements();
+}
+
+cTemplateViewChannel::~cTemplateViewChannel() {
+}
+
+void cTemplateViewChannel::SetViewElements(void) {
+ viewElementsAllowed.insert("background");
+ viewElementsAllowed.insert("channelinfo");
+ viewElementsAllowed.insert("channelgroup");
+ viewElementsAllowed.insert("epginfo");
+ viewElementsAllowed.insert("progressbar");
+ viewElementsAllowed.insert("progressbarback");
+ viewElementsAllowed.insert("statusinfo");
+ viewElementsAllowed.insert("screenresolution");
+ viewElementsAllowed.insert("signalquality");
+ viewElementsAllowed.insert("signalqualityback");
+ viewElementsAllowed.insert("scrapercontent");
+ viewElementsAllowed.insert("datetime");
+ viewElementsAllowed.insert("message");
+}
+
+string cTemplateViewChannel::GetViewElementName(eViewElement ve) {
+ string name;
+ switch (ve) {
+ case veBackground:
+ name = "Background";
+ break;
+ case veChannelInfo:
+ name = "ChannelInfo";
+ break;
+ case veChannelGroup:
+ name = "ChannelGroup";
+ break;
+ case veEpgInfo:
+ name = "EpgInfo";
+ break;
+ case veProgressBar:
+ name = "ProgressBar";
+ break;
+ case veProgressBarBack:
+ name = "ProgressBar Background";
+ break;
+ case veStatusInfo:
+ name = "StatusInfo";
+ break;
+ case veScreenResolution:
+ name = "Screen Resolution";
+ break;
+ case veSignalQuality:
+ name = "Signal Quality";
+ break;
+ case veSignalQualityBack:
+ name = "Signal Quality Background";
+ break;
+ case veScraperContent:
+ name = "Scraper Content";
+ break;
+ case veDateTime:
+ name = "DateTime";
+ break;
+ case veMessage:
+ name = "Message";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ };
+ return name;
+}
+
+void cTemplateViewChannel::AddPixmap(string sViewElement, cTemplatePixmap *pix, bool debugViewElement) {
+ eViewElement ve = veUndefined;
+
+ if (!sViewElement.compare("background")) {
+ ve = veBackground;
+ } else if (!sViewElement.compare("channelinfo")) {
+ ve = veChannelInfo;
+ } else if (!sViewElement.compare("channelgroup")) {
+ ve = veChannelGroup;
+ } else if (!sViewElement.compare("epginfo")) {
+ ve = veEpgInfo;
+ } else if (!sViewElement.compare("progressbar")) {
+ ve = veProgressBar;
+ } else if (!sViewElement.compare("progressbarback")) {
+ ve = veProgressBarBack;
+ } else if (!sViewElement.compare("statusinfo")) {
+ ve = veStatusInfo;
+ } else if (!sViewElement.compare("screenresolution")) {
+ ve = veScreenResolution;
+ } else if (!sViewElement.compare("signalquality")) {
+ ve = veSignalQuality;
+ } else if (!sViewElement.compare("signalqualityback")) {
+ ve = veSignalQualityBack;
+ } else if (!sViewElement.compare("scrapercontent")) {
+ ve = veScraperContent;
+ } else if (!sViewElement.compare("datetime")) {
+ ve = veDateTime;
+ } else if (!sViewElement.compare("message")) {
+ ve = veMessage;
+ }
+
+ if (ve == veUndefined) {
+ esyslog("skindesigner: unknown ViewElement in displaychannel: %s", sViewElement.c_str());
+ return;
+ }
+
+ pix->SetGlobals(globals);
+
+ map < eViewElement, cTemplateViewElement* >::iterator hit = viewElements.find(ve);
+ if (hit == viewElements.end()) {
+ cTemplateViewElement *viewElement = new cTemplateViewElement();
+ viewElement->AddPixmap(pix);
+ viewElements.insert(pair< eViewElement, cTemplateViewElement*>(ve, viewElement));
+ if (debugViewElement)
+ viewElement->ActivateDebugTokens();
+ } else {
+ (hit->second)->AddPixmap(pix);
+ }
+}
+
+/************************************************************************************
+* cTemplateViewMenu
+************************************************************************************/
+
+cTemplateViewMenu::cTemplateViewMenu(void) {
+
+ viewName = "displaymenu";
+ //definition of allowed parameters for class itself
+ set<string> attributes;
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ funcsAllowed.insert(pair< string, set<string> >(viewName, attributes));
+
+ string subViewName = "menudefault";
+ //definition of allowed parameters for subtemplate menumain
+ attributes.clear();
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(subViewName, attributes));
+
+ subViewName = "menumain";
+ //definition of allowed parameters for subtemplate menumain
+ attributes.clear();
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(subViewName, attributes));
+
+ subViewName = "menusetup";
+ //definition of allowed parameters for subtemplate menumain
+ attributes.clear();
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(subViewName, attributes));
+
+ subViewName = "menuschedules";
+ //definition of allowed parameters for subtemplate menumain
+ attributes.clear();
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(subViewName, attributes));
+
+ subViewName = "menuchannels";
+ //definition of allowed parameters for subtemplate menumain
+ attributes.clear();
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(subViewName, attributes));
+
+ subViewName = "menutimers";
+ //definition of allowed parameters for subtemplate menumain
+ attributes.clear();
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(subViewName, attributes));
+
+ subViewName = "menurecordings";
+ //definition of allowed parameters for subtemplate menumain
+ attributes.clear();
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(subViewName, attributes));
+
+ subViewName = "menudetailedepg";
+ //definition of allowed parameters for subtemplate menumain
+ attributes.clear();
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(subViewName, attributes));
+
+ subViewName = "menudetailedrecording";
+ //definition of allowed parameters for subtemplate menumain
+ attributes.clear();
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(subViewName, attributes));
+
+ subViewName = "menudetailedtext";
+ //definition of allowed parameters for subtemplate menumain
+ attributes.clear();
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(subViewName, attributes));
+
+ //definition of allowed parameters for timerlist viewlist
+ attributes.clear();
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("orientation");
+ attributes.insert("align");
+ attributes.insert("numlistelements");
+ funcsAllowed.insert(pair< string, set<string> >("timerlist", attributes));
+
+ //definition of allowed parameters for menuitems viewlist
+ attributes.clear();
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("orientation");
+ attributes.insert("align");
+ attributes.insert("menuitemwidth");
+ attributes.insert("determinatefont");
+ attributes.insert("numlistelements");
+ funcsAllowed.insert(pair< string, set<string> >("menuitems", attributes));
+
+ //definition of allowed parameters for currentitems viewlist
+ attributes.clear();
+ attributes.insert("delay");
+ attributes.insert("fadetime");
+ funcsAllowed.insert(pair< string, set<string> >("currentelement", attributes));
+
+ //definition of allowed parameters for viewtab
+ attributes.clear();
+ attributes.insert("debug");
+ attributes.insert("name");
+ attributes.insert("condition");
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("layer");
+ attributes.insert("transparency");
+ attributes.insert("scrollheight");
+ funcsAllowed.insert(pair< string, set<string> >("tab", attributes));
+
+ SetSubViews();
+ SetViewElements();
+ SetViewLists();
+
+}
+
+cTemplateViewMenu::~cTemplateViewMenu() {
+}
+
+void cTemplateViewMenu::SetSubViews(void) {
+ subViewsAllowed.insert("menudefault");
+ subViewsAllowed.insert("menumain");
+ subViewsAllowed.insert("menusetup");
+ subViewsAllowed.insert("menuschedules");
+ subViewsAllowed.insert("menutimers");
+ subViewsAllowed.insert("menurecordings");
+ subViewsAllowed.insert("menuchannels");
+ subViewsAllowed.insert("menudetailedepg");
+ subViewsAllowed.insert("menudetailedrecording");
+ subViewsAllowed.insert("menudetailedtext");
+}
+
+void cTemplateViewMenu::SetViewElements(void) {
+ viewElementsAllowed.insert("background");
+ viewElementsAllowed.insert("datetime");
+ viewElementsAllowed.insert("header");
+ viewElementsAllowed.insert("colorbuttons");
+ viewElementsAllowed.insert("message");
+ viewElementsAllowed.insert("discusage");
+ viewElementsAllowed.insert("systemload");
+ viewElementsAllowed.insert("timers");
+ viewElementsAllowed.insert("devices");
+ viewElementsAllowed.insert("scrollbar");
+ viewElementsAllowed.insert("detailheader");
+ viewElementsAllowed.insert("tablabels");
+}
+
+void cTemplateViewMenu::SetViewLists(void) {
+ viewListsAllowed.insert("timerlist");
+ viewListsAllowed.insert("menuitems");
+}
+
+string cTemplateViewMenu::GetSubViewName(eSubView sv) {
+ string name;
+ switch (sv) {
+ case svMenuDefault:
+ name = "Default Menu";
+ break;
+ case svMenuMain:
+ name = "Main Menu";
+ break;
+ case svMenuSetup:
+ name = "Setup Menu";
+ break;
+ case svMenuSchedules:
+ name = "Schedules Menu";
+ break;
+ case svMenuTimers:
+ name = "Timers Menu";
+ break;
+ case svMenuRecordings:
+ name = "Recordings Menu";
+ break;
+ case svMenuChannels:
+ name = "Channels Menu";
+ break;
+ case svMenuDetailedEpg:
+ name = "Detailed EPG";
+ break;
+ case svMenuDetailedRecording:
+ name = "Detailed Recording";
+ break;
+ case svMenuDetailedText:
+ name = "Detailed Text";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ };
+ return name;
+}
+
+
+string cTemplateViewMenu::GetViewElementName(eViewElement ve) {
+ string name;
+ switch (ve) {
+ case veBackground:
+ name = "Background";
+ break;
+ case veDateTime:
+ name = "DateTime";
+ break;
+ case veHeader:
+ name = "Header";
+ break;
+ case veButtons:
+ name = "Color Buttons";
+ break;
+ case veMessage:
+ name = "Message";
+ break;
+ case veDiscUsage:
+ name = "Disc Usage";
+ break;
+ case veSystemLoad:
+ name = "System Load";
+ break;
+ case veTimers:
+ name = "Timers";
+ break;
+ case veDevices:
+ name = "Devices";
+ break;
+ case veMenuItem:
+ name = "Menu Item";
+ break;
+ case veMenuCurrentItemDetail:
+ name = "Menu Current Item Detail";
+ break;
+ case veScrollbar:
+ name = "Scrollbar";
+ break;
+ case veDetailHeader:
+ name = "Detail header";
+ break;
+ case veTabLabels:
+ name = "tab labels";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ };
+ return name;
+}
+
+string cTemplateViewMenu::GetViewListName(eViewList vl) {
+ string name;
+ switch (vl) {
+ case vlTimerList:
+ name = "Timer List";
+ break;
+ case vlMenuItem:
+ name = "Menu Item";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ };
+ return name;
+}
+
+void cTemplateViewMenu::AddSubView(string sSubView, cTemplateView *subView) {
+ eSubView sv = svUndefined;
+
+ if (!sSubView.compare("menumain")) {
+ sv = svMenuMain;
+ } else if (!sSubView.compare("menudefault")) {
+ sv = svMenuDefault;
+ } else if (!sSubView.compare("menuschedules")) {
+ sv = svMenuSchedules;
+ } else if (!sSubView.compare("menusetup")) {
+ sv = svMenuSetup;
+ } else if (!sSubView.compare("menuschedules")) {
+ sv = svMenuSchedules;
+ } else if (!sSubView.compare("menutimers")) {
+ sv = svMenuTimers;
+ } else if (!sSubView.compare("menurecordings")) {
+ sv = svMenuRecordings;
+ } else if (!sSubView.compare("menuchannels")) {
+ sv = svMenuChannels;
+ } else if (!sSubView.compare("menudetailedepg")) {
+ sv = svMenuDetailedEpg;
+ } else if (!sSubView.compare("menudetailedrecording")) {
+ sv = svMenuDetailedRecording;
+ } else if (!sSubView.compare("menudetailedtext")) {
+ sv = svMenuDetailedText;
+ }
+
+ if (sv == svUndefined) {
+ esyslog("skindesigner: unknown SubView in displayMenu: %s", sSubView.c_str());
+ return;
+ }
+ subView->SetGlobals(globals);
+ subViews.insert(pair<eSubView, cTemplateView*>(sv, subView));
+}
+
+void cTemplateViewMenu::AddPixmap(string sViewElement, cTemplatePixmap *pix, bool debugViewElement) {
+ eViewElement ve = veUndefined;
+
+ if (!sViewElement.compare("background")) {
+ ve = veBackground;
+ } else if (!sViewElement.compare("datetime")) {
+ ve = veDateTime;
+ } else if (!sViewElement.compare("header")) {
+ ve = veHeader;
+ } else if (!sViewElement.compare("colorbuttons")) {
+ ve = veButtons;
+ } else if (!sViewElement.compare("message")) {
+ ve = veMessage;
+ } else if (!sViewElement.compare("discusage")) {
+ ve = veDiscUsage;
+ } else if (!sViewElement.compare("systemload")) {
+ ve = veSystemLoad;
+ } else if (!sViewElement.compare("timers")) {
+ ve = veTimers;
+ } else if (!sViewElement.compare("devices")) {
+ ve = veDevices;
+ } else if (!sViewElement.compare("scrollbar")) {
+ ve = veScrollbar;
+ } else if (!sViewElement.compare("detailheader")) {
+ ve = veDetailHeader;
+ } else if (!sViewElement.compare("tablabels")) {
+ ve = veTabLabels;
+ }
+
+ if (ve == veUndefined) {
+ esyslog("skindesigner: unknown ViewElement in displayMenu: %s", sViewElement.c_str());
+ return;
+ }
+
+ pix->SetGlobals(globals);
+
+ map < eViewElement, cTemplateViewElement* >::iterator hit = viewElements.find(ve);
+ if (hit == viewElements.end()) {
+ cTemplateViewElement *viewElement = new cTemplateViewElement();
+ viewElement->AddPixmap(pix);
+ viewElements.insert(pair< eViewElement, cTemplateViewElement*>(ve, viewElement));
+ if (debugViewElement)
+ viewElement->ActivateDebugTokens();
+ } else {
+ (hit->second)->AddPixmap(pix);
+ }
+}
+
+void cTemplateViewMenu::AddViewList(string sViewList, cTemplateViewList *viewList) {
+
+ eViewList vl = vlUndefined;
+ if (!sViewList.compare("timerlist")) {
+ vl = vlTimerList;
+ } else if (!sViewList.compare("menuitems")) {
+ vl = vlMenuItem;
+ }
+
+ if (vl == vlUndefined) {
+ esyslog("skindesigner: unknown ViewList in displaymenu: %s", sViewList.c_str());
+ return;
+ }
+
+ viewList->SetGlobals(globals);
+ viewLists.insert(pair< eViewList, cTemplateViewList*>(vl, viewList));
+}
+
+void cTemplateViewMenu::AddViewTab(cTemplateViewTab *viewTab) {
+ viewTabs.push_back(viewTab);
+}
+
+/************************************************************************************
+* cTemplateViewMessage
+************************************************************************************/
+
+cTemplateViewMessage::cTemplateViewMessage(void) {
+
+ viewName = "displaymessage";
+ //definition of allowed parameters for class itself
+ set<string> attributes;
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(viewName, attributes));
+
+ SetViewElements();
+}
+
+cTemplateViewMessage::~cTemplateViewMessage() {
+}
+
+void cTemplateViewMessage::SetViewElements(void) {
+ viewElementsAllowed.insert("background");
+ viewElementsAllowed.insert("message");
+}
+
+string cTemplateViewMessage::GetViewElementName(eViewElement ve) {
+ string name;
+ switch (ve) {
+ case veBackground:
+ name = "Background";
+ break;
+ case veMessage:
+ name = "Message";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ };
+ return name;
+}
+
+void cTemplateViewMessage::AddPixmap(string sViewElement, cTemplatePixmap *pix, bool debugViewElement) {
+ eViewElement ve = veUndefined;
+
+ if (!sViewElement.compare("background")) {
+ ve = veBackground;
+ } else if (!sViewElement.compare("message")) {
+ ve = veMessage;
+ }
+
+ if (ve == veUndefined) {
+ esyslog("skindesigner: unknown ViewElement in displaymessage: %s", sViewElement.c_str());
+ return;
+ }
+
+ pix->SetGlobals(globals);
+
+ map < eViewElement, cTemplateViewElement* >::iterator hit = viewElements.find(ve);
+ if (hit == viewElements.end()) {
+ cTemplateViewElement *viewElement = new cTemplateViewElement();
+ viewElement->AddPixmap(pix);
+ viewElements.insert(pair< eViewElement, cTemplateViewElement*>(ve, viewElement));
+ if (debugViewElement)
+ viewElement->ActivateDebugTokens();
+ } else {
+ (hit->second)->AddPixmap(pix);
+ }
+}
+
+/************************************************************************************
+* cTemplateViewReplay
+************************************************************************************/
+
+cTemplateViewReplay::cTemplateViewReplay(void) {
+
+ viewName = "displayreplay";
+ //definition of allowed parameters for class itself
+ set<string> attributes;
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(viewName, attributes));
+
+ SetViewElements();
+}
+
+cTemplateViewReplay::~cTemplateViewReplay() {
+}
+
+void cTemplateViewReplay::SetViewElements(void) {
+ viewElementsAllowed.insert("background");
+ viewElementsAllowed.insert("backgroundmodeonly");
+ viewElementsAllowed.insert("datetime");
+ viewElementsAllowed.insert("rectitle");
+ viewElementsAllowed.insert("recinfo");
+ viewElementsAllowed.insert("scrapercontent");
+ viewElementsAllowed.insert("currenttime");
+ viewElementsAllowed.insert("totaltime");
+ viewElementsAllowed.insert("progressbar");
+ viewElementsAllowed.insert("cutmarks");
+ viewElementsAllowed.insert("controlicons");
+ viewElementsAllowed.insert("controliconsmodeonly");
+ viewElementsAllowed.insert("jump");
+ viewElementsAllowed.insert("message");
+}
+
+string cTemplateViewReplay::GetViewElementName(eViewElement ve) {
+ string name;
+ switch (ve) {
+ case veBackground:
+ name = "Background";
+ break;
+ case veDateTime:
+ name = "DateTime";
+ break;
+ case veRecTitle:
+ name = "Recording Title";
+ break;
+ case veRecInfo:
+ name = "Recording Information";
+ break;
+ case veRecCurrent:
+ name = "Recording current Time";
+ break;
+ case veRecTotal:
+ name = "Recording total Time";
+ break;
+ case veRecProgressBar:
+ name = "Rec Progress Bar";
+ break;
+ case veCuttingMarks:
+ name = "Cutting Marks";
+ break;
+ case veControlIcons:
+ name = "Control Icons";
+ break;
+ case veControlIconsModeOnly:
+ name = "Control Icons Mode only";
+ break;
+ case veBackgroundModeOnly:
+ name = "Background Mode only";
+ break;
+ case veRecJump:
+ name = "Recording Jump";
+ break;
+ case veScraperContent:
+ name = "Scraper Content";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ };
+ return name;
+}
+
+void cTemplateViewReplay::AddPixmap(string sViewElement, cTemplatePixmap *pix, bool debugViewElement) {
+ eViewElement ve = veUndefined;
+
+ if (!sViewElement.compare("background")) {
+ ve = veBackground;
+ } else if (!sViewElement.compare("datetime")) {
+ ve = veDateTime;
+ } else if (!sViewElement.compare("rectitle")) {
+ ve = veRecTitle;
+ } else if (!sViewElement.compare("recinfo")) {
+ ve = veRecInfo;
+ } else if (!sViewElement.compare("scrapercontent")) {
+ ve = veScraperContent;
+ } else if (!sViewElement.compare("currenttime")) {
+ ve = veRecCurrent;
+ } else if (!sViewElement.compare("totaltime")) {
+ ve = veRecTotal;
+ } else if (!sViewElement.compare("progressbar")) {
+ ve = veRecProgressBar;
+ } else if (!sViewElement.compare("cutmarks")) {
+ ve = veCuttingMarks;
+ } else if (!sViewElement.compare("controlicons")) {
+ ve = veControlIcons;
+ } else if (!sViewElement.compare("controliconsmodeonly")) {
+ ve = veControlIconsModeOnly;
+ } else if (!sViewElement.compare("backgroundmodeonly")) {
+ ve = veBackgroundModeOnly;
+ } else if (!sViewElement.compare("jump")) {
+ ve = veRecJump;
+ } else if (!sViewElement.compare("message")) {
+ ve = veMessage;
+ }
+
+ if (ve == veUndefined) {
+ esyslog("skindesigner: unknown ViewElement in displayreplay: %s", sViewElement.c_str());
+ return;
+ }
+
+ pix->SetGlobals(globals);
+
+ map < eViewElement, cTemplateViewElement* >::iterator hit = viewElements.find(ve);
+ if (hit == viewElements.end()) {
+ cTemplateViewElement *viewElement = new cTemplateViewElement();
+ viewElement->AddPixmap(pix);
+ viewElements.insert(pair< eViewElement, cTemplateViewElement*>(ve, viewElement));
+ if (debugViewElement)
+ viewElement->ActivateDebugTokens();
+ } else {
+ (hit->second)->AddPixmap(pix);
+ }
+}
+
+
+/************************************************************************************
+* cTemplateViewVolume
+************************************************************************************/
+
+cTemplateViewVolume::cTemplateViewVolume(void) {
+
+ viewName = "displayvolume";
+ //definition of allowed parameters for class itself
+ set<string> attributes;
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(viewName, attributes));
+
+ SetViewElements();
+}
+
+cTemplateViewVolume::~cTemplateViewVolume() {
+}
+
+void cTemplateViewVolume::SetViewElements(void) {
+ viewElementsAllowed.insert("background");
+ viewElementsAllowed.insert("volume");
+}
+
+string cTemplateViewVolume::GetViewElementName(eViewElement ve) {
+ string name;
+ switch (ve) {
+ case veBackground:
+ name = "Background";
+ break;
+ case veVolume:
+ name = "Volume";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ };
+ return name;
+}
+
+void cTemplateViewVolume::AddPixmap(string sViewElement, cTemplatePixmap *pix, bool debugViewElement) {
+ eViewElement ve = veUndefined;
+
+ if (!sViewElement.compare("background")) {
+ ve = veBackground;
+ } else if (!sViewElement.compare("volume")) {
+ ve = veVolume;
+ }
+
+ if (ve == veUndefined) {
+ esyslog("skindesigner: unknown ViewElement in displayvolume: %s", sViewElement.c_str());
+ return;
+ }
+
+ pix->SetGlobals(globals);
+
+ map < eViewElement, cTemplateViewElement* >::iterator hit = viewElements.find(ve);
+ if (hit == viewElements.end()) {
+ cTemplateViewElement *viewElement = new cTemplateViewElement();
+ viewElement->AddPixmap(pix);
+ viewElements.insert(pair< eViewElement, cTemplateViewElement*>(ve, viewElement));
+ if (debugViewElement)
+ viewElement->ActivateDebugTokens();
+ } else {
+ (hit->second)->AddPixmap(pix);
+ }
+}
+
+/************************************************************************************
+* cTemplateViewAudioTracks
+************************************************************************************/
+
+cTemplateViewAudioTracks::cTemplateViewAudioTracks(void) {
+
+ viewName = "displayaudiotracks";
+ //definition of allowed parameters for class itself
+ set<string> attributes;
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("fadetime");
+ attributes.insert("scaletvx");
+ attributes.insert("scaletvy");
+ attributes.insert("scaletvwidth");
+ attributes.insert("scaletvheight");
+ funcsAllowed.insert(pair< string, set<string> >(viewName, attributes));
+
+ //definition of allowed parameters for menuitems viewlist
+ attributes.clear();
+ attributes.insert("x");
+ attributes.insert("y");
+ attributes.insert("width");
+ attributes.insert("height");
+ attributes.insert("orientation");
+ attributes.insert("align");
+ attributes.insert("menuitemwidth");
+ attributes.insert("numlistelements");
+ funcsAllowed.insert(pair< string, set<string> >("menuitems", attributes));
+
+ SetViewElements();
+ SetViewLists();
+}
+
+cTemplateViewAudioTracks::~cTemplateViewAudioTracks() {
+}
+
+void cTemplateViewAudioTracks::SetViewElements(void) {
+ viewElementsAllowed.insert("background");
+ viewElementsAllowed.insert("header");
+}
+
+void cTemplateViewAudioTracks::SetViewLists(void) {
+ viewListsAllowed.insert("menuitems");
+}
+
+string cTemplateViewAudioTracks::GetViewElementName(eViewElement ve) {
+ string name;
+ switch (ve) {
+ case veBackground:
+ name = "Background";
+ break;
+ case veHeader:
+ name = "Header";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ };
+ return name;
+}
+
+string cTemplateViewAudioTracks::GetViewListName(eViewList vl) {
+ string name;
+ switch (vl) {
+ case vlMenuItem:
+ name = "Menu Item";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ };
+ return name;
+}
+
+void cTemplateViewAudioTracks::AddPixmap(string sViewElement, cTemplatePixmap *pix, bool debugViewElement) {
+ eViewElement ve = veUndefined;
+
+ if (!sViewElement.compare("background")) {
+ ve = veBackground;
+ } else if(!sViewElement.compare("header")) {
+ ve = veHeader;
+ }
+
+ if (ve == veUndefined) {
+ esyslog("skindesigner: unknown ViewElement in displayaudiotracks: %s", sViewElement.c_str());
+ return;
+ }
+
+ pix->SetGlobals(globals);
+
+ map < eViewElement, cTemplateViewElement* >::iterator hit = viewElements.find(ve);
+ if (hit == viewElements.end()) {
+ cTemplateViewElement *viewElement = new cTemplateViewElement();
+ viewElement->AddPixmap(pix);
+ viewElements.insert(pair< eViewElement, cTemplateViewElement*>(ve, viewElement));
+ if (debugViewElement)
+ viewElement->ActivateDebugTokens();
+ } else {
+ (hit->second)->AddPixmap(pix);
+ }
+}
+
+void cTemplateViewAudioTracks::AddViewList(string sViewList, cTemplateViewList *viewList) {
+
+ eViewList vl = vlUndefined;
+ if (!sViewList.compare("menuitems")) {
+ vl = vlMenuItem;
+ }
+
+ if (vl == vlUndefined) {
+ esyslog("skindesigner: unknown ViewList in displaymenu: %s", sViewList.c_str());
+ return;
+ }
+
+ viewList->SetGlobals(globals);
+ viewLists.insert(pair< eViewList, cTemplateViewList*>(vl, viewList));
+}
diff --git a/libtemplate/templateview.h b/libtemplate/templateview.h
new file mode 100644
index 0000000..414deaa
--- /dev/null
+++ b/libtemplate/templateview.h
@@ -0,0 +1,198 @@
+#ifndef __TEMPLATEVIEW_H
+#define __TEMPLATEVIEW_H
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <sstream>
+
+#include "templateviewelement.h"
+#include "templateviewlist.h"
+#include "templatepixmap.h"
+#include "templateviewtab.h"
+#include "templatefunction.h"
+
+using namespace std;
+
+// --- cTemplateView -------------------------------------------------------------
+
+enum eSubView {
+ svUndefined,
+ svMenuDefault,
+ svMenuMain,
+ svMenuSetup,
+ svMenuSchedules,
+ svMenuTimers,
+ svMenuRecordings,
+ svMenuChannels,
+ svMenuDetailedEpg,
+ svMenuDetailedRecording,
+ svMenuDetailedText
+};
+
+class cTemplateView {
+private:
+protected:
+ cGlobals *globals;
+ //view parameters
+ string viewName;
+ cTemplateFunction *parameters;
+ int containerX;
+ int containerY;
+ int containerWidth;
+ int containerHeight;
+ //basic view data structures
+ map < eViewElement, cTemplateViewElement* > viewElements;
+ map < eViewList, cTemplateViewList* > viewLists;
+ map < eSubView, cTemplateView* > subViews;
+ vector< cTemplateViewTab* > viewTabs;
+ //helpers to iterate data structures
+ map < eViewElement, cTemplateViewElement* >::iterator veIt;
+ map < eViewList, cTemplateViewList* >::iterator vlIt;
+ map < eSubView, cTemplateView* >::iterator svIt;
+ vector< cTemplateViewTab* >::iterator vtIt;
+ //helpers to check valid xml templates
+ set<string> subViewsAllowed;
+ set<string> viewElementsAllowed;
+ set<string> viewListsAllowed;
+ map < string, set < string > > funcsAllowed;
+ void SetFunctionDefinitions(void);
+public:
+ cTemplateView(void);
+ virtual ~cTemplateView(void);
+ virtual string GetSubViewName(eSubView sv) { return ""; };
+ virtual string GetViewElementName(eViewElement ve) { return ""; };
+ virtual string GetViewListName(eViewList vl) { return ""; };
+ virtual void AddSubView(string sSubView, cTemplateView *subView) {};
+ virtual void AddPixmap(string sViewElement, cTemplatePixmap *pix, bool debugViewElement) {};
+ virtual void AddViewList(string sViewList, cTemplateViewList *viewList) {};
+ virtual void AddViewTab(cTemplateViewTab *viewTab) {};
+ //Setter Functions
+ void SetGlobals(cGlobals *globals) { this->globals = globals; };
+ void SetParameters(vector<pair<string, string> > &params);
+ void SetContainer(int x, int y, int width, int height);
+ //access view elements
+ cTemplateViewElement *GetViewElement(eViewElement ve);
+ void InitViewElementIterator(void);
+ cTemplateViewElement *GetNextViewElement(void);
+ //access list elements
+ cTemplateViewList *GetViewList(eViewList vl);
+ void InitViewListIterator(void);
+ cTemplateViewList *GetNextViewList(void);
+ //access tabs
+ void InitViewTabIterator(void);
+ cTemplateViewTab *GetNextViewTab(void);
+ //access sub views
+ cTemplateView *GetSubView(eSubView sv);
+ void InitSubViewIterator(void);
+ cTemplateView *GetNextSubView(void);
+ //Getter Functions
+ const char *GetViewName(void) { return viewName.c_str(); };
+ int GetNumericParameter(eParamType type);
+ cRect GetOsdSize(void);
+ int GetNumPixmaps(void);
+ int GetNumPixmapsViewElement(eViewElement ve);
+ int GetNumListViewMenuItems(void);
+ bool GetScalingWindow(cRect &scalingWindow);
+ //Checks for parsing template XML files
+ bool ValidSubView(const char *subView);
+ bool ValidViewElement(const char *viewElement);
+ bool ValidViewList(const char *viewList);
+ bool ValidFunction(const char *func);
+ bool ValidAttribute(const char *func, const char *att);
+ //Caching
+ void Translate(void);
+ void PreCache(bool isSubview);
+ //Debug
+ void Debug(void);
+};
+
+// --- cTemplateViewChannel -------------------------------------------------------------
+
+class cTemplateViewChannel : public cTemplateView {
+private:
+ void SetViewElements(void);
+ void SetViewLists(void);
+public:
+ cTemplateViewChannel(void);
+ virtual ~cTemplateViewChannel(void);
+ string GetViewElementName(eViewElement ve);
+ void AddPixmap(string viewElement, cTemplatePixmap *pix, bool debugViewElement);
+};
+
+// --- cTemplateViewMenu -------------------------------------------------------------
+
+class cTemplateViewMenu : public cTemplateView {
+private:
+ void SetSubViews(void);
+ void SetViewElements(void);
+ void SetViewLists(void);
+public:
+ cTemplateViewMenu(void);
+ virtual ~cTemplateViewMenu(void);
+ string GetSubViewName(eSubView sv);
+ string GetViewElementName(eViewElement ve);
+ string GetViewListName(eViewList vl);
+ void AddSubView(string sSubView, cTemplateView *subView);
+ void AddPixmap(string viewElement, cTemplatePixmap *pix, bool debugViewElement);
+ void AddViewList(string sViewList, cTemplateViewList *viewList);
+ void AddViewTab(cTemplateViewTab *viewTab);
+};
+
+// --- cTemplateViewMessage -------------------------------------------------------------
+
+class cTemplateViewMessage : public cTemplateView {
+private:
+ void SetViewElements(void);
+public:
+ cTemplateViewMessage(void);
+ virtual ~cTemplateViewMessage(void);
+ string GetViewElementName(eViewElement ve);
+ void AddPixmap(string viewElement, cTemplatePixmap *pix, bool debugViewElement);
+};
+
+// --- cTemplateViewReplay -------------------------------------------------------------
+
+class cTemplateViewReplay : public cTemplateView {
+private:
+ void SetViewElements(void);
+public:
+ cTemplateViewReplay(void);
+ virtual ~cTemplateViewReplay(void);
+ string GetViewElementName(eViewElement ve);
+ void AddPixmap(string viewElement, cTemplatePixmap *pix, bool debugViewElement);
+};
+
+// --- cTemplateViewVolume -------------------------------------------------------------
+
+class cTemplateViewVolume : public cTemplateView {
+private:
+ void SetViewElements(void);
+public:
+ cTemplateViewVolume(void);
+ virtual ~cTemplateViewVolume(void);
+ string GetViewElementName(eViewElement ve);
+ void AddPixmap(string viewElement, cTemplatePixmap *pix, bool debugViewElement);
+};
+
+// --- cTemplateViewAudioTracks -------------------------------------------------------------
+
+class cTemplateViewAudioTracks : public cTemplateView {
+private:
+ void SetViewElements(void);
+ void SetViewLists(void);
+public:
+ cTemplateViewAudioTracks(void);
+ virtual ~cTemplateViewAudioTracks(void);
+ string GetViewElementName(eViewElement ve);
+ string GetViewListName(eViewList vl);
+ void AddPixmap(string viewElement, cTemplatePixmap *pix, bool debugViewElement);
+ void AddViewList(string sViewList, cTemplateViewList *viewList);
+};
+
+#endif //__TEMPLATEVIEW_H
diff --git a/libtemplate/templateviewelement.c b/libtemplate/templateviewelement.c
new file mode 100644
index 0000000..87aeade
--- /dev/null
+++ b/libtemplate/templateviewelement.c
@@ -0,0 +1,128 @@
+#include "templateviewelement.h"
+#include "../config.h"
+
+cTemplateViewElement::cTemplateViewElement(void) {
+ debugTokens = false;
+ parameters = NULL;
+ containerX = 0;
+ containerY = 0;
+ containerWidth = 0;
+ containerHeight = 0;
+ pixOffset = -1;
+}
+
+cTemplateViewElement::~cTemplateViewElement(void) {
+ if (parameters)
+ delete parameters;
+ for (vector<cTemplatePixmap*>::iterator it = viewPixmaps.begin(); it != viewPixmaps.end(); it++) {
+ delete (*it);
+ }
+}
+
+void cTemplateViewElement::SetContainer(int x, int y, int width, int height) {
+ containerX = x;
+ containerY = y;
+ containerWidth = width;
+ containerHeight = height;
+}
+
+void cTemplateViewElement::SetGlobals(cGlobals *globals) {
+ this->globals = globals;
+ for (vector<cTemplatePixmap*>::iterator pix = viewPixmaps.begin(); pix != viewPixmaps.end(); pix++) {
+ (*pix)->SetGlobals(globals);
+ }
+}
+
+void cTemplateViewElement::SetParameters(vector<pair<string, string> > &params) {
+ parameters = new cTemplateFunction(ftViewElement);
+ parameters->SetGlobals(globals);
+ parameters->SetParameters(params);
+}
+
+bool cTemplateViewElement::CalculateParameters(void) {
+ if (!parameters)
+ return true;
+ bool paramsValid = true;
+ parameters->SetContainer(containerX, containerY, containerWidth, containerHeight);
+ parameters->SetGlobals(globals);
+ paramsValid = parameters->CalculateParameters();
+
+ return paramsValid;
+}
+
+bool cTemplateViewElement::CalculatePixmapParameters(void) {
+ bool paramsValid = true;
+ for (vector<cTemplatePixmap*>::iterator pix = viewPixmaps.begin(); pix != viewPixmaps.end(); pix++) {
+ (*pix)->SetContainer(containerX, containerY, containerWidth, containerHeight);
+ (*pix)->SetGlobals(globals);
+ paramsValid = paramsValid && (*pix)->CalculateParameters();
+ }
+ return paramsValid;
+}
+
+bool cTemplateViewElement::CalculatePixmapParametersList(int orientation, int numElements) {
+ bool paramsValid = true;
+ for (vector<cTemplatePixmap*>::iterator pix = viewPixmaps.begin(); pix != viewPixmaps.end(); pix++) {
+ (*pix)->SetContainer(containerX, containerY, containerWidth, containerHeight);
+ (*pix)->SetGlobals(globals);
+ if (orientation == orHorizontal) {
+ if (numElements > 0) {
+ int width = containerWidth / numElements;
+ (*pix)->SetWidth(width);
+ }
+ } else if (orientation == orVertical) {
+ if (numElements > 0) {
+ int height = containerHeight / numElements;
+ (*pix)->SetHeight(height);
+ }
+ }
+ paramsValid = paramsValid && (*pix)->CalculateParameters();
+ }
+ return paramsValid;
+}
+
+int cTemplateViewElement::GetNumericParameter(eParamType type) {
+ if (!parameters)
+ return -1;
+ return parameters->GetNumericParameter(type);
+}
+
+void cTemplateViewElement::InitIterator(void) {
+ pixIterator = viewPixmaps.begin();
+}
+
+cTemplatePixmap *cTemplateViewElement::GetNextPixmap(void) {
+ if (pixIterator == viewPixmaps.end())
+ return NULL;
+ cTemplatePixmap *pix = *pixIterator;
+ pixIterator++;
+ return pix;
+}
+
+cTemplateFunction *cTemplateViewElement::GetFunction(string name) {
+ InitIterator();
+ cTemplatePixmap *pix = NULL;
+ while (pix = GetNextPixmap()) {
+ pix->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = pix->GetNextFunction()) {
+ if (func->GetType() == ftDrawText) {
+ string funcName = func->GetParameter(ptName);
+ if (!funcName.compare(name))
+ return func;
+ } else {
+ continue;
+ }
+ }
+ }
+ return NULL;
+}
+
+void cTemplateViewElement::Debug(void) {
+ esyslog("skindesigner: viewelement container size x: %d, y: %d, width: %d, height %d", containerX, containerY, containerWidth, containerHeight);
+ if (parameters)
+ parameters->Debug();
+ for (vector<cTemplatePixmap*>::iterator it = viewPixmaps.begin(); it != viewPixmaps.end(); it++) {
+ (*it)->Debug();
+ }
+} \ No newline at end of file
diff --git a/libtemplate/templateviewelement.h b/libtemplate/templateviewelement.h
new file mode 100644
index 0000000..84db627
--- /dev/null
+++ b/libtemplate/templateviewelement.h
@@ -0,0 +1,99 @@
+#ifndef __TEMPLATEVIEWELEMENT_H
+#define __TEMPLATEVIEWELEMENT_H
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <sstream>
+
+#include "templatepixmap.h"
+#include "templatefunction.h"
+
+using namespace std;
+
+// --- cTemplateViewElement -------------------------------------------------------------
+
+enum eViewElement {
+ //Common ViewElements
+ veUndefined,
+ veBackground,
+ veDateTime,
+ veMessage,
+ //DisplayChannel ViewElements
+ veChannelInfo,
+ veChannelGroup,
+ veEpgInfo,
+ veProgressBar,
+ veProgressBarBack,
+ veStatusInfo,
+ veScreenResolution,
+ veSignalQuality,
+ veSignalQualityBack,
+ veScraperContent,
+ //DisplayMenu ViewElements
+ veHeader,
+ veButtons,
+ veDiscUsage,
+ veSystemLoad,
+ veTimers,
+ veDevices,
+ veMenuItem,
+ veMenuCurrentItemDetail,
+ veScrollbar,
+ veDetailHeader,
+ veTabLabels,
+ //DisplayReplay ViewElements
+ veRecTitle,
+ veRecInfo,
+ veRecCurrent,
+ veRecTotal,
+ veRecProgressBar,
+ veCuttingMarks,
+ veControlIcons,
+ veControlIconsModeOnly,
+ veBackgroundModeOnly,
+ veRecJump,
+ //DisplayVolume ViewElements
+ veVolume
+};
+
+class cTemplateViewElement {
+protected:
+ bool debugTokens;
+ cGlobals *globals;
+ cTemplateFunction *parameters;
+ int containerX;
+ int containerY;
+ int containerWidth;
+ int containerHeight;
+ vector<cTemplatePixmap*> viewPixmaps;
+ vector<cTemplatePixmap*>::iterator pixIterator;
+ int pixOffset;
+public:
+ cTemplateViewElement(void);
+ virtual ~cTemplateViewElement(void);
+ void SetParameters(vector<pair<string, string> > &params);
+ bool CalculateParameters(void);
+ bool CalculatePixmapParameters(void);
+ bool CalculatePixmapParametersList(int orientation, int numElements);
+ int GetNumericParameter(eParamType type);
+ void AddPixmap(cTemplatePixmap *pix) { viewPixmaps.push_back(pix); };
+ virtual void SetGlobals(cGlobals *globals);
+ void SetContainer(int x, int y, int width, int height);
+ void SetPixOffset(int offset) { pixOffset = offset; };
+ int GetPixOffset(void) { return pixOffset; };
+ virtual int GetNumPixmaps(void) { return viewPixmaps.size(); };
+ void InitIterator(void);
+ cTemplatePixmap *GetNextPixmap(void);
+ cTemplateFunction *GetFunction(string name);
+ void ActivateDebugTokens(void) {debugTokens = true; };
+ bool DebugTokens(void) { return debugTokens; };
+ virtual void Debug(void);
+};
+
+#endif //__TEMPLATEVIEWELEMENT_H \ No newline at end of file
diff --git a/libtemplate/templateviewlist.c b/libtemplate/templateviewlist.c
new file mode 100644
index 0000000..808a89f
--- /dev/null
+++ b/libtemplate/templateviewlist.c
@@ -0,0 +1,138 @@
+#include "templateviewlist.h"
+#include "../config.h"
+
+cTemplateViewList::cTemplateViewList(void) : cTemplateViewElement() {
+ listElement = NULL;
+ currentElement = NULL;
+}
+
+cTemplateViewList::~cTemplateViewList(void) {
+ if (listElement)
+ delete listElement;
+ if (currentElement)
+ delete currentElement;
+}
+
+void cTemplateViewList::SetGlobals(cGlobals *globals) {
+ cTemplateViewElement::SetGlobals(globals);
+ if (listElement)
+ listElement->SetGlobals(globals);
+ if (currentElement)
+ currentElement->SetGlobals(globals);
+}
+
+bool cTemplateViewList::CalculateListParameters(void) {
+ if (!parameters)
+ return false;
+ parameters->SetContainer(containerX, containerY, containerWidth, containerHeight);
+ parameters->SetGlobals(globals);
+ bool paramsValid = parameters->CalculateParameters();
+ if (!listElement)
+ return false;
+ listElement->SetContainer(parameters->GetNumericParameter(ptX),
+ parameters->GetNumericParameter(ptY),
+ parameters->GetNumericParameter(ptWidth),
+ parameters->GetNumericParameter(ptHeight));
+ paramsValid = listElement->CalculateParameters();
+ paramsValid = listElement->CalculatePixmapParametersList(parameters->GetNumericParameter(ptOrientation),
+ parameters->GetNumericParameter(ptNumElements));
+ if (!currentElement)
+ return paramsValid;
+ currentElement->SetContainer(parameters->GetNumericParameter(ptX),
+ parameters->GetNumericParameter(ptY),
+ parameters->GetNumericParameter(ptWidth),
+ parameters->GetNumericParameter(ptHeight));
+ paramsValid = currentElement->CalculateParameters();
+ paramsValid = currentElement->CalculatePixmapParameters();
+ currentElement->SetPixOffset(0);
+ return paramsValid;
+}
+
+bool cTemplateViewList::CalculateListParameters(map < string, int > *intTokens) {
+ if (!parameters)
+ return false;
+ parameters->ClearDynamicParameters();
+ parameters->SetIntTokens(intTokens);
+ parameters->ParseParameters();
+ parameters->UnsetIntTokens();
+
+ listElement->SetContainer(parameters->GetNumericParameter(ptX),
+ parameters->GetNumericParameter(ptY),
+ parameters->GetNumericParameter(ptWidth),
+ parameters->GetNumericParameter(ptHeight));
+ bool paramsValid = listElement->CalculateParameters();
+ paramsValid = listElement->CalculatePixmapParametersList(parameters->GetNumericParameter(ptOrientation),
+ parameters->GetNumericParameter(ptNumElements));
+ return paramsValid;
+}
+
+int cTemplateViewList::GetAverageFontWidth(void) {
+ int defaultAverageFontWidth = 20;
+
+ if (!listElement)
+ return defaultAverageFontWidth;
+
+ int numItems = GetNumericParameter(ptNumElements);
+ int listHeight = GetNumericParameter(ptHeight);
+ if (listHeight <= 0)
+ return defaultAverageFontWidth;
+ int itemHeight = (double)listHeight / (double)numItems;
+ string fontFuncName = parameters->GetParameter(ptDeterminateFont);
+
+ cTemplateFunction *fontFunc = listElement->GetFunction(fontFuncName);
+ if (!fontFunc)
+ return defaultAverageFontWidth;
+
+ string fontNameToken = fontFunc->GetParameter(ptFont);
+ string paramFontSize = fontFunc->GetParameter(ptFontSize);
+
+ string fontName = "";
+ if ((fontNameToken.find("{") == 0) && (fontNameToken.find("}") == (fontNameToken.size()-1))) {
+ fontNameToken = fontNameToken.substr(1, fontNameToken.size()-2);
+ map<string,string>::iterator hit = globals->fonts.find(fontNameToken);
+ if (hit != globals->fonts.end()) {
+ fontName = hit->second;
+ } else {
+ map<string,string>::iterator def = globals->fonts.find("vdrOsd");
+ if (def == globals->fonts.end())
+ return defaultAverageFontWidth;
+ fontName = def->second;
+ }
+ } else {
+ //if no token, directly use input
+ fontName = fontNameToken;
+ }
+
+ cNumericParameter pFontSize(paramFontSize);
+ pFontSize.SetGlobals(globals);
+ pFontSize.SetAreaSize(1000, itemHeight);
+ pFontSize.SetVertical();
+ int fontSize = pFontSize.Parse(paramFontSize);
+ if (!pFontSize.Valid())
+ return defaultAverageFontWidth;
+
+ int averageFontWidth = fontManager->Width(fontName, fontSize, "x") + 3;
+ return averageFontWidth;
+}
+
+int cTemplateViewList::GetMenuItemWidth(void) {
+ return GetNumericParameter(ptMenuItemWidth);
+}
+
+
+int cTemplateViewList::GetNumPixmaps(void) {
+ if (!listElement)
+ return 0;
+ return listElement->GetNumPixmaps();
+}
+
+void cTemplateViewList::Debug(void) {
+ if (parameters)
+ parameters->Debug();
+ esyslog("skindesigner: --- listelement: ");
+ if (listElement)
+ listElement->Debug();
+ esyslog("skindesigner: --- currentelement: ");
+ if (currentElement)
+ currentElement->Debug();
+} \ No newline at end of file
diff --git a/libtemplate/templateviewlist.h b/libtemplate/templateviewlist.h
new file mode 100644
index 0000000..8998384
--- /dev/null
+++ b/libtemplate/templateviewlist.h
@@ -0,0 +1,49 @@
+#ifndef __TEMPLATEVIEWLIST_H
+#define __TEMPLATEVIEWLIST_H
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <sstream>
+
+#include "templateviewelement.h"
+
+using namespace std;
+
+// --- cTemplateViewList -------------------------------------------------------------
+
+enum eViewList {
+ vlUndefined,
+ //DisplayChannel ViewLists
+ vlDvbDeviceInfoList,
+ //DisplayMenu ViewLists
+ vlTimerList,
+ vlMenuItem
+};
+
+class cTemplateViewList : public cTemplateViewElement {
+private:
+ cTemplateViewElement *listElement;
+ cTemplateViewElement *currentElement;
+public:
+ cTemplateViewList(void);
+ ~cTemplateViewList(void);
+ void SetGlobals(cGlobals *globals);
+ void AddListElement(cTemplateViewElement *listElement) { this->listElement = listElement; };
+ void AddCurrentElement(cTemplateViewElement *currentElement) { this->currentElement = currentElement; };
+ bool CalculateListParameters(void);
+ bool CalculateListParameters(map < string, int > *intTokens);
+ cTemplateViewElement *GetListElement(void) { return listElement; };
+ cTemplateViewElement *GetListElementCurrent(void) { return currentElement; };
+ int GetAverageFontWidth(void);
+ int GetMenuItemWidth(void);
+ int GetNumPixmaps(void);
+ void Debug(void);
+};
+
+#endif //__TEMPLATEVIEWLIST_H \ No newline at end of file
diff --git a/libtemplate/templateviewtab.c b/libtemplate/templateviewtab.c
new file mode 100644
index 0000000..1e9f463
--- /dev/null
+++ b/libtemplate/templateviewtab.c
@@ -0,0 +1,38 @@
+#include "templateviewtab.h"
+
+cTemplateViewTab::cTemplateViewTab(void) : cTemplatePixmap() {
+ scrollStep = -1;
+}
+
+cTemplateViewTab::~cTemplateViewTab(void) {
+}
+
+int cTemplateViewTab::GetScrollStep(void) {
+ if (scrollStep > 0)
+ return scrollStep;
+ int pixWidth = GetNumericParameter(ptWidth);
+ int pixHeight = GetNumericParameter(ptHeight);
+ string scrollHeight = parameters->GetParameter(ptScrollHeight);
+
+ cNumericParameter p(scrollHeight);
+ p.SetAreaSize(pixWidth, pixHeight);
+ string parsedValue = "";
+ scrollStep = p.Parse(parsedValue);
+ if (scrollStep < 1)
+ scrollStep = 50;
+ return scrollStep;
+}
+
+string cTemplateViewTab::GetName(void) {
+ return parameters->GetParameter(ptName);
+}
+
+void cTemplateViewTab::SetName(string trans) {
+ parameters->SetParameter(ptName, trans);
+}
+
+void cTemplateViewTab::Debug(void) {
+ esyslog("skindesigner: cTemplateViewTab Debug %s", GetName().c_str());
+ cTemplatePixmap::Debug();
+ esyslog("skindesigner: -------------------------------------------------------");
+}
diff --git a/libtemplate/templateviewtab.h b/libtemplate/templateviewtab.h
new file mode 100644
index 0000000..8514cad
--- /dev/null
+++ b/libtemplate/templateviewtab.h
@@ -0,0 +1,31 @@
+#ifndef __TEMPLATEVIEWTAB_H
+#define __TEMPLATEVIEWTAB_H
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+
+#include "templatepixmap.h"
+
+using namespace std;
+
+// --- cTemplateViewTab -------------------------------------------------------------
+
+class cTemplateViewTab : public cTemplatePixmap {
+private:
+ int scrollStep;
+public:
+ cTemplateViewTab(void);
+ ~cTemplateViewTab(void);
+ int GetScrollStep(void);
+ string GetName(void);
+ void SetName(string trans);
+ void Debug(void);
+};
+
+#endif //__TEMPLATEVIEWTAB_H \ No newline at end of file
diff --git a/libtemplate/xmlparser.c b/libtemplate/xmlparser.c
new file mode 100644
index 0000000..f9a723a
--- /dev/null
+++ b/libtemplate/xmlparser.c
@@ -0,0 +1,728 @@
+#include "xmlparser.h"
+#include "../config.h"
+
+using namespace std;
+
+void SkinDesignerXMLErrorHandler (void * userData, xmlErrorPtr error) {
+ esyslog("skindesigner: Error in XML: %s", error->message);
+}
+
+cXmlParser::cXmlParser(void) {
+ doc = NULL;
+ root = NULL;
+ ctxt = NULL;
+
+ xmlInitParser();
+ initGenericErrorDefaultFunc(NULL);
+ xmlSetStructuredErrorFunc(NULL, SkinDesignerXMLErrorHandler);
+ ctxt = xmlNewParserCtxt();
+}
+
+cXmlParser::~cXmlParser() {
+ DeleteDocument();
+ xmlFreeParserCtxt(ctxt);
+ xmlCleanupParser();
+}
+
+/*********************************************************************
+* PUBLIC Functions
+*********************************************************************/
+bool cXmlParser::ReadView(cTemplateView *view, string xmlFile) {
+ this->view = view;
+
+ string xmlPath = GetPath(xmlFile);
+
+ if (ctxt == NULL) {
+ esyslog("skindesigner: Failed to allocate parser context");
+ return false;
+ }
+
+ doc = xmlCtxtReadFile(ctxt, xmlPath.c_str(), NULL, XML_PARSE_NOENT | XML_PARSE_DTDVALID);
+
+ if (doc == NULL) {
+ esyslog("skindesigner: ERROR: TemplateView %s not parsed successfully.", xmlPath.c_str());
+ return false;
+ }
+ if (ctxt->valid == 0) {
+ esyslog("skindesigner: Failed to validate %s", xmlPath.c_str());
+ return false;
+ }
+
+ root = xmlDocGetRootElement(doc);
+
+ if (root == NULL) {
+ esyslog("skindesigner: ERROR: TemplateView %s is empty", xmlPath.c_str());
+ return false;
+ }
+
+ if (xmlStrcmp(root->name, (const xmlChar *) view->GetViewName())) {
+ return false;
+ }
+ return true;
+}
+
+bool cXmlParser::ReadGlobals(cGlobals *globals, string xmlFile) {
+ this->globals = globals;
+
+ string xmlPath = GetPath(xmlFile);
+
+ if (ctxt == NULL) {
+ esyslog("skindesigner: Failed to allocate parser context");
+ return false;
+ }
+
+ doc = xmlCtxtReadFile(ctxt, xmlPath.c_str(), NULL, XML_PARSE_NOENT | XML_PARSE_DTDVALID);
+
+ if (doc == NULL ) {
+ esyslog("skindesigner: ERROR: Globals %s not parsed successfully.", xmlPath.c_str());
+ return false;
+ }
+
+ root = xmlDocGetRootElement(doc);
+
+ if (ctxt->valid == 0) {
+ esyslog("skindesigner: Failed to validate %s", xmlPath.c_str());
+ return false;
+ }
+
+ if (root == NULL) {
+ esyslog("skindesigner: ERROR: Globals %s is empty", xmlPath.c_str());
+ return false;
+ }
+
+ if (xmlStrcmp(root->name, (const xmlChar *) "globals")) {
+ return false;
+ }
+ return true;
+}
+
+bool cXmlParser::ParseView(void) {
+ vector<pair<string, string> > rootAttribs;
+ ParseAttributes(root->properties, root, rootAttribs);
+
+ if (!view)
+ return false;
+
+ view->SetParameters(rootAttribs);
+
+ xmlNodePtr node = root->xmlChildrenNode;
+
+ while (node != NULL) {
+
+ if (node->type != XML_ELEMENT_NODE) {
+ node = node->next;
+ continue;
+ }
+
+ if (view->ValidSubView((const char*)node->name)) {
+ ParseSubView(node);
+ } else if (view->ValidViewElement((const char*)node->name)) {
+ bool debugViewElement = DebugViewElement(node);
+ ParseViewElement(node->name, node->xmlChildrenNode, debugViewElement);
+ } else if (view->ValidViewList((const char*)node->name)) {
+ ParseViewList(node);
+ } else {
+ return false;
+ }
+
+ node = node->next;
+ }
+
+ return true;
+
+}
+
+bool cXmlParser::ParseGlobals(void) {
+ xmlNodePtr node = root->xmlChildrenNode;
+
+ while (node != NULL) {
+ if (node->type != XML_ELEMENT_NODE) {
+ node = node->next;
+ continue;
+ }
+ if (!xmlStrcmp(node->name, (const xmlChar *) "colors")) {
+ ParseGlobalColors(node->xmlChildrenNode);
+ node = node->next;
+ continue;
+ } else if (!xmlStrcmp(node->name, (const xmlChar *) "variables")) {
+ ParseGlobalVariables(node->xmlChildrenNode);
+ node = node->next;
+ continue;
+ } else if (!xmlStrcmp(node->name, (const xmlChar *) "fonts")) {
+ ParseGlobalFonts(node->xmlChildrenNode);
+ node = node->next;
+ continue;
+ } else if (!xmlStrcmp(node->name, (const xmlChar *) "translations")) {
+ ParseTranslations(node->xmlChildrenNode);
+ node = node->next;
+ continue;
+ }
+ node = node->next;
+ }
+
+ return true;
+
+}
+
+void cXmlParser::DeleteDocument(void) {
+ if (doc) {
+ xmlFreeDoc(doc);
+ doc = NULL;
+ }
+}
+
+/*********************************************************************
+* PRIVATE Functions
+*********************************************************************/
+
+string cXmlParser::GetPath(string xmlFile) {
+ return *cString::sprintf("%s%s/xmlfiles/%s", *config.skinPath, Setup.OSDTheme, xmlFile.c_str());
+}
+
+void cXmlParser::ParseGlobalColors(xmlNodePtr node) {
+ if (!node)
+ return;
+
+ while (node != NULL) {
+
+ if (node->type != XML_ELEMENT_NODE) {
+ node = node->next;
+ continue;
+ }
+ if (xmlStrcmp(node->name, (const xmlChar *) "color")) {
+ node = node->next;
+ continue;
+ }
+ xmlAttrPtr attr = node->properties;
+ if (attr == NULL) {
+ node = node->next;
+ continue;
+ }
+ xmlChar *colName = NULL;
+ xmlChar *colValue = NULL;
+ bool ok = false;
+ while (NULL != attr) {
+ if (xmlStrcmp(attr->name, (const xmlChar *) "name")) {
+ attr = attr->next;
+ continue;
+ }
+ ok = true;
+ colName = xmlGetProp(node, attr->name);
+ attr = attr->next;
+ }
+ if (ok) {
+ colValue = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
+ if (colName && colValue)
+ InsertColor((const char*)colName, (const char*)colValue);
+ }
+ if (colName)
+ xmlFree(colName);
+ if (colValue)
+ xmlFree(colValue);
+ node = node->next;
+ }
+}
+
+void cXmlParser::InsertColor(string name, string value) {
+ if (value.size() != 8)
+ return;
+ std::stringstream str;
+ str << value;
+ tColor colVal;
+ str >> std::hex >> colVal;
+ globals->colors.insert(pair<string, tColor>(name, colVal));
+}
+
+void cXmlParser::ParseGlobalVariables(xmlNodePtr node) {
+ if (!node)
+ return;
+
+ while (node != NULL) {
+
+ if (node->type != XML_ELEMENT_NODE) {
+ node = node->next;
+ continue;
+ }
+ if (xmlStrcmp(node->name, (const xmlChar *) "var")) {
+ node = node->next;
+ continue;
+ }
+ xmlAttrPtr attr = node->properties;
+ if (attr == NULL) {
+ node = node->next;
+ continue;
+ }
+ xmlChar *varName = NULL;
+ xmlChar *varType = NULL;
+ xmlChar *varValue = NULL;
+ while (NULL != attr) {
+ if (!xmlStrcmp(attr->name, (const xmlChar *) "name")) {
+ varName = xmlGetProp(node, attr->name);
+ } else if (!xmlStrcmp(attr->name, (const xmlChar *) "type")) {
+ varType = xmlGetProp(node, attr->name);
+ } else {
+ attr = attr->next;
+ continue;
+ }
+ attr = attr->next;
+ }
+ varValue = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
+ if (varName && varType && varValue)
+ InsertVariable((const char*)varName, (const char*)varType, (const char*)varValue);
+ if (varName)
+ xmlFree(varName);
+ if (varType)
+ xmlFree(varType);
+ if (varValue)
+ xmlFree(varValue);
+ node = node->next;
+ }
+}
+
+void cXmlParser::InsertVariable(string name, string type, string value) {
+ if (!type.compare("int")) {
+ int val = atoi(value.c_str());
+ globals->intVars.insert(pair<string, int>(name, val));
+ } else if (!type.compare("string")) {
+ globals->stringVars.insert(pair<string, string>(name, value));
+ }
+}
+
+void cXmlParser::ParseGlobalFonts(xmlNodePtr node) {
+ if (!node)
+ return;
+
+ while (node != NULL) {
+
+ if (node->type != XML_ELEMENT_NODE) {
+ node = node->next;
+ continue;
+ }
+ if (xmlStrcmp(node->name, (const xmlChar *) "font")) {
+ node = node->next;
+ continue;
+ }
+ xmlAttrPtr attr = node->properties;
+ if (attr == NULL) {
+ node = node->next;
+ continue;
+ }
+ xmlChar *fontName = NULL;
+ xmlChar *fontValue = NULL;
+ bool ok = false;
+ while (NULL != attr) {
+ if (xmlStrcmp(attr->name, (const xmlChar *) "name")) {
+ attr = attr->next;
+ continue;
+ }
+ ok = true;
+ fontName = xmlGetProp(node, attr->name);
+ attr = attr->next;
+ }
+ if (ok) {
+ fontValue = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
+ if (fontName && fontValue)
+ globals->fonts.insert(pair<string, string>((const char*)fontName, (const char*)fontValue));
+ }
+ if (fontName)
+ xmlFree(fontName);
+ if (fontValue)
+ xmlFree(fontValue);
+ node = node->next;
+ }
+}
+
+void cXmlParser::ParseTranslations(xmlNodePtr node) {
+ if (!node)
+ return;
+
+ while (node != NULL) {
+
+ if (node->type != XML_ELEMENT_NODE) {
+ node = node->next;
+ continue;
+ }
+ if (xmlStrcmp(node->name, (const xmlChar *) "token")) {
+ node = node->next;
+ continue;
+ }
+ xmlAttrPtr attr = node->properties;
+ if (attr == NULL) {
+ node = node->next;
+ continue;
+ }
+ xmlChar *tokenName;
+ bool ok = false;
+ while (NULL != attr) {
+ if (xmlStrcmp(attr->name, (const xmlChar *) "name")) {
+ attr = attr->next;
+ continue;
+ }
+ ok = true;
+ tokenName = xmlGetProp(node, attr->name);
+ attr = attr->next;
+ }
+ if (!ok)
+ continue;
+ map < string, string > tokenTranslations;
+ xmlNodePtr nodeTrans = node->xmlChildrenNode;
+ while (nodeTrans != NULL) {
+ if (nodeTrans->type != XML_ELEMENT_NODE) {
+ nodeTrans = nodeTrans->next;
+ continue;
+ }
+ xmlChar *language = NULL;
+ if (xmlStrcmp(nodeTrans->name, (const xmlChar *) "trans")) {
+ nodeTrans = nodeTrans->next;
+ continue;
+ }
+ xmlAttrPtr attrTrans = nodeTrans->properties;
+ if (attrTrans == NULL) {
+ nodeTrans = nodeTrans->next;
+ continue;
+ }
+ ok = false;
+
+ while (NULL != attrTrans) {
+ if (!ok && xmlStrcmp(attrTrans->name, (const xmlChar *) "lang")) {
+ attrTrans = attrTrans->next;
+ continue;
+ }
+ ok = true;
+ language = xmlGetProp(nodeTrans, attrTrans->name);
+ attrTrans = attrTrans->next;
+ }
+ if (!ok)
+ continue;
+ xmlChar *value = NULL;
+ value = xmlNodeListGetString(doc, nodeTrans->xmlChildrenNode, 1);
+ if (language && value)
+ tokenTranslations.insert(pair<string, string>((const char*)language, (const char*)value));
+ if (language)
+ xmlFree(language);
+ if (value)
+ xmlFree(value);
+ nodeTrans = nodeTrans->next;
+ }
+ globals->translations.insert(pair<string, map < string, string > >((const char*)tokenName, tokenTranslations));
+ xmlFree(tokenName);
+ node = node->next;
+ }
+}
+
+bool cXmlParser::ParseSubView(xmlNodePtr node) {
+ if (!node)
+ return false;
+
+ if (!view)
+ return false;
+
+ cTemplateView *subView = new cTemplateViewMenu();
+ view->AddSubView((const char*)node->name, subView);
+
+ vector<pair<string, string> > subViewAttribs;
+ ParseAttributes(node->properties, node, subViewAttribs);
+
+ subView->SetParameters(subViewAttribs);
+
+ xmlNodePtr childNode = node->xmlChildrenNode;
+
+ while (childNode != NULL) {
+
+ if (childNode->type != XML_ELEMENT_NODE) {
+ childNode = childNode->next;
+ continue;
+ }
+
+ if (subView->ValidViewElement((const char*)childNode->name)) {
+ bool debugViewElement = DebugViewElement(childNode);
+ ParseViewElement(childNode->name, childNode->xmlChildrenNode, debugViewElement, subView);
+ } else if (subView->ValidViewList((const char*)childNode->name)) {
+ ParseViewList(childNode, subView);
+ } else if (!xmlStrcmp(childNode->name, (const xmlChar *) "tab")) {
+ ParseViewTab(childNode, subView);
+ } else {
+ return false;
+ }
+
+ childNode = childNode->next;
+ }
+
+
+
+ return true;
+
+}
+
+void cXmlParser::ParseViewElement(const xmlChar * viewElement, xmlNodePtr node, bool debugVE, cTemplateView *subView) {
+ if (!node)
+ return;
+
+ if (!view)
+ return;
+
+ if (debugVE) {
+ dsyslog("skindesigner: activating debugging of viewElement %s", (const char*)viewElement);
+ }
+
+ while (node != NULL) {
+
+ if (node->type != XML_ELEMENT_NODE) {
+ node = node->next;
+ continue;
+ }
+
+ if (xmlStrcmp(node->name, (const xmlChar *) "area") && xmlStrcmp(node->name, (const xmlChar *) "areascroll")) {
+ esyslog("skindesigner: invalid tag \"%s\"", node->name);
+ node = node->next;
+ continue;
+ }
+
+ xmlAttrPtr attr = node->properties;
+ vector<pair<string, string> > attribs;
+ ParseAttributes(attr, node, attribs);
+
+ cTemplatePixmap *pix = new cTemplatePixmap();
+ if (!xmlStrcmp(node->name, (const xmlChar *) "areascroll")) {
+ pix->SetScrolling();
+ }
+ pix->SetParameters(attribs);
+ ParseFunctionCalls(node->xmlChildrenNode, pix);
+ if (subView)
+ subView->AddPixmap((const char*)viewElement, pix, debugVE);
+ else
+ view->AddPixmap((const char*)viewElement, pix, debugVE);
+
+ node = node->next;
+ }
+}
+
+void cXmlParser::ParseViewList(xmlNodePtr parentNode, cTemplateView *subView) {
+ if (!parentNode || !view)
+ return;
+
+ xmlAttrPtr attr = parentNode->properties;
+ vector<pair<string, string> > attribs;
+ ParseAttributes(attr, parentNode, attribs);
+
+ cTemplateViewList *viewList = new cTemplateViewList();
+ viewList->SetGlobals(globals);
+ viewList->SetParameters(attribs);
+
+ xmlNodePtr node = parentNode->xmlChildrenNode;
+
+ while (node != NULL) {
+
+ if (node->type != XML_ELEMENT_NODE) {
+ node = node->next;
+ continue;
+ }
+
+ if (!xmlStrcmp(node->name, (const xmlChar *) "currentelement")) {
+ xmlNodePtr childNode = node->xmlChildrenNode;
+ if (!childNode)
+ continue;
+ cTemplateViewElement *currentElement = new cTemplateViewElement();
+ xmlAttrPtr attrCur = node->properties;
+ vector<pair<string, string> > attribsCur;
+ ParseAttributes(attrCur, node, attribsCur);
+ currentElement->SetGlobals(globals);
+ currentElement->SetParameters(attribsCur);
+ bool debugCurrent = false;
+ for (vector<pair<string, string> >::iterator it = attribsCur.begin(); it != attribsCur.end(); it++) {
+ if (!(it->first).compare("debug")) {
+ debugCurrent = true;
+ break;
+ }
+ }
+ if (debugCurrent)
+ currentElement->ActivateDebugTokens();
+ while (childNode != NULL) {
+ if (childNode->type != XML_ELEMENT_NODE) {
+ childNode = childNode->next;
+ continue;
+ }
+ if ((!xmlStrcmp(childNode->name, (const xmlChar *) "area")) || (!xmlStrcmp(childNode->name, (const xmlChar *) "areascroll"))) {
+ xmlAttrPtr attrPix = childNode->properties;
+ vector<pair<string, string> > attribsPix;
+ ParseAttributes(attrPix, childNode, attribsPix);
+ cTemplatePixmap *pix = new cTemplatePixmap();
+ pix->SetParameters(attribsPix);
+ ParseFunctionCalls(childNode->xmlChildrenNode, pix);
+ if (!xmlStrcmp(childNode->name, (const xmlChar *) "areascroll")) {
+ pix->SetScrolling();
+ }
+ currentElement->AddPixmap(pix);
+ }
+ childNode = childNode->next;
+ }
+ viewList->AddCurrentElement(currentElement);
+ } else if (!xmlStrcmp(node->name, (const xmlChar *) "listelement")) {
+ bool debugViewList = DebugViewElement(node);
+ xmlNodePtr childNode = node->xmlChildrenNode;
+ if (!childNode)
+ continue;
+ cTemplateViewElement *listElement = new cTemplateViewElement();
+ if (debugViewList)
+ listElement->ActivateDebugTokens();
+ while (childNode != NULL) {
+ if (childNode->type != XML_ELEMENT_NODE) {
+ childNode = childNode->next;
+ continue;
+ }
+ if ((!xmlStrcmp(childNode->name, (const xmlChar *) "area")) || (!xmlStrcmp(childNode->name, (const xmlChar *) "areascroll"))) {
+ xmlAttrPtr attrPix = childNode->properties;
+ vector<pair<string, string> > attribsPix;
+ ParseAttributes(attrPix, childNode, attribsPix);
+ cTemplatePixmap *pix = new cTemplatePixmap();
+ pix->SetParameters(attribsPix);
+ ParseFunctionCalls(childNode->xmlChildrenNode, pix);
+ if (!xmlStrcmp(childNode->name, (const xmlChar *) "areascroll")) {
+ pix->SetScrolling();
+ }
+ listElement->AddPixmap(pix);
+ }
+ childNode = childNode->next;
+ }
+ viewList->AddListElement(listElement);
+ } else {
+ node = node->next;
+ continue;
+ }
+ node = node->next;
+ }
+ if (subView)
+ subView->AddViewList((const char*)parentNode->name, viewList);
+ else
+ view->AddViewList((const char*)parentNode->name, viewList);
+}
+
+void cXmlParser::ParseViewTab(xmlNodePtr parentNode, cTemplateView *subView) {
+ if (!parentNode || !view || !subView)
+ return;
+
+ xmlAttrPtr attr = parentNode->properties;
+ vector<pair<string, string> > attribs;
+ ParseAttributes(attr, parentNode, attribs);
+
+ cTemplateViewTab *viewTab = new cTemplateViewTab();
+ viewTab->SetGlobals(globals);
+ viewTab->SetParameters(attribs);
+ viewTab->SetScrolling();
+ xmlNodePtr node = parentNode->xmlChildrenNode;
+ ParseFunctionCalls(node, viewTab);
+
+ subView->AddViewTab(viewTab);
+}
+
+void cXmlParser::ParseFunctionCalls(xmlNodePtr node, cTemplatePixmap *pix) {
+ if (!node)
+ return;
+
+ if (!view)
+ return;
+
+ while (node != NULL) {
+
+ if (node->type != XML_ELEMENT_NODE) {
+ node = node->next;
+ continue;
+ }
+
+ if (!xmlStrcmp(node->name, (const xmlChar *) "loop")) {
+ xmlNodePtr childNode = node->xmlChildrenNode;
+ if (!childNode)
+ continue;
+ xmlAttrPtr attr = node->properties;
+ vector<pair<string, string> > attribs;
+ ParseAttributes(attr, node, attribs);
+ cTemplateLoopFunction *loopFunc = new cTemplateLoopFunction();
+ loopFunc->SetParameters(attribs);
+ ParseLoopFunctionCalls(childNode, loopFunc);
+ pix->AddLoopFunction(loopFunc);
+ node = node->next;
+ } else if (view->ValidFunction((const char*)node->name)) {
+ xmlAttrPtr attr = node->properties;
+ vector<pair<string, string> > attribs;
+ ParseAttributes(attr, node, attribs);
+ pix->AddFunction((const char*)node->name, attribs);
+ node = node->next;
+ } else {
+ node = node->next;
+ continue;
+ }
+
+ }
+}
+
+void cXmlParser::ParseLoopFunctionCalls(xmlNodePtr node, cTemplateLoopFunction *loopFunc) {
+ if (!node)
+ return;
+
+ if (!view)
+ return;
+
+ while (node != NULL) {
+
+ if (node->type != XML_ELEMENT_NODE) {
+ node = node->next;
+ continue;
+ }
+ if (view->ValidFunction((const char*)node->name)) {
+ xmlAttrPtr attr = node->properties;
+ vector<pair<string, string> > attribs;
+ ParseAttributes(attr, node, attribs);
+ loopFunc->AddFunction((const char*)node->name, attribs);
+ node = node->next;
+ } else {
+ node = node->next;
+ continue;
+ }
+
+ }
+}
+
+bool cXmlParser::ParseAttributes(xmlAttrPtr attr, xmlNodePtr node, vector<pair<string, string> > &attribs) {
+ if (attr == NULL) {
+ return false;
+ }
+
+ if (!view)
+ return false;
+
+ while (NULL != attr) {
+
+ string name = (const char*)attr->name;
+ if (!name.compare("debug")) {
+ attribs.push_back(pair<string, string>((const char*)attr->name, "true"));
+ attr = attr->next;
+ continue;
+ }
+
+ xmlChar *value = NULL;
+ value = xmlGetProp(node, attr->name);
+ if (!view->ValidAttribute((const char*)node->name, (const char*)attr->name)) {
+ attr = attr->next;
+ if (value)
+ xmlFree(value);
+ continue;
+ }
+ if (value)
+ attribs.push_back(pair<string, string>((const char*)attr->name, (const char*)value));
+ attr = attr->next;
+ if (value)
+ xmlFree(value);
+ }
+ return true;
+}
+
+bool cXmlParser::DebugViewElement(xmlNodePtr node) {
+ xmlAttrPtr attr = node->properties;
+ vector<pair<string, string> > attribs;
+ ParseAttributes(attr, node, attribs);
+ for (vector<pair<string, string> >::iterator it = attribs.begin(); it != attribs.end(); it++) {
+ if (!(it->first).compare("debug"))
+ return true;
+ }
+ return false;
+}
diff --git a/libtemplate/xmlparser.h b/libtemplate/xmlparser.h
new file mode 100644
index 0000000..ecdcca3
--- /dev/null
+++ b/libtemplate/xmlparser.h
@@ -0,0 +1,56 @@
+#ifndef __XMLPARSER_H
+#define __XMLPARSER_H
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlerror.h>
+#include <vdr/plugin.h>
+
+#include "templateview.h"
+#include "templateviewlist.h"
+#include "templateviewtab.h"
+
+using namespace std;
+
+// --- cXmlParser -------------------------------------------------------------
+
+class cXmlParser {
+private:
+ cTemplateView *view;
+ cGlobals *globals;
+ xmlParserCtxtPtr ctxt;
+ xmlDocPtr doc;
+ xmlNodePtr root;
+ string GetPath(string xmlFile);
+ void ParseGlobalColors(xmlNodePtr node);
+ void InsertColor(string name, string value);
+ void ParseGlobalVariables(xmlNodePtr node);
+ void InsertVariable(string name, string type, string value);
+ void ParseGlobalFonts(xmlNodePtr node);
+ void ParseTranslations(xmlNodePtr node);
+ bool ParseSubView(xmlNodePtr node);
+ void ParseViewElement(const xmlChar * viewElement, xmlNodePtr node, bool debugVE, cTemplateView *subView = NULL);
+ void ParseViewList(xmlNodePtr parentNode, cTemplateView *subView = NULL);
+ void ParseViewTab(xmlNodePtr parentNode, cTemplateView *subView);
+ void ParseFunctionCalls(xmlNodePtr node, cTemplatePixmap *pix);
+ void ParseLoopFunctionCalls(xmlNodePtr node, cTemplateLoopFunction *loopFunc);
+ bool ParseAttributes(xmlAttrPtr attr, xmlNodePtr node, vector<pair<string, string> > &attribs);
+ bool DebugViewElement(xmlNodePtr node);
+public:
+ cXmlParser(void);
+ virtual ~cXmlParser(void);
+ bool ReadView(cTemplateView *view, string xmlFile);
+ bool ReadGlobals(cGlobals *globals, string xmlFile);
+ bool ParseView(void);
+ bool ParseGlobals(void);
+ void DeleteDocument(void);
+};
+
+#endif //__XMLPARSER_H \ No newline at end of file
diff --git a/services/epgsearch.h b/services/epgsearch.h
new file mode 100644
index 0000000..0c38793
--- /dev/null
+++ b/services/epgsearch.h
@@ -0,0 +1,167 @@
+/*
+Copyright (C) 2004-2007 Christian Wieninger
+
+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
+of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+
+The author can be reached at cwieninger@gmx.de
+
+The project's page is at http://winni.vdr-developer.org/epgsearch
+*/
+
+#ifndef EPGSEARCHSERVICES_INC
+#define EPGSEARCHSERVICES_INC
+
+// Added by Andreas Mair (mail _AT_ andreas _DOT_ vdr-developer _DOT_ org)
+#define EPGSEARCH_SEARCHRESULTS_SERVICE_STRING_ID "Epgsearch-searchresults-v1.0"
+#define EPGSEARCH_LASTCONFLICTINFO_SERVICE_STRING_ID "Epgsearch-lastconflictinfo-v1.0"
+
+#include <string>
+#include <list>
+#include <memory>
+#include <set>
+#include <vdr/osdbase.h>
+
+// Data structure for service "Epgsearch-search-v1.0"
+struct Epgsearch_search_v1_0
+{
+// in
+ char* query; // search term
+ int mode; // search mode (0=phrase, 1=and, 2=or, 3=regular expression)
+ int channelNr; // channel number to search in (0=any)
+ bool useTitle; // search in title
+ bool useSubTitle; // search in subtitle
+ bool useDescription; // search in description
+// out
+ cOsdMenu* pResultMenu; // pointer to the menu of results
+};
+
+// Data structure for service "Epgsearch-exttimeredit-v1.0"
+struct Epgsearch_exttimeredit_v1_0
+{
+// in
+ cTimer* timer; // pointer to the timer to edit
+ bool bNew; // flag that indicates, if this is a new timer or an existing one
+ const cEvent* event; // pointer to the event corresponding to this timer (may be NULL)
+// out
+ cOsdMenu* pTimerMenu; // pointer to the menu of results
+};
+
+// Data structure for service "Epgsearch-updatesearchtimers-v1.0"
+struct Epgsearch_updatesearchtimers_v1_0
+{
+// in
+ bool showMessage; // inform via osd when finished?
+};
+
+// Data structure for service "Epgsearch-osdmessage-v1.0"
+struct Epgsearch_osdmessage_v1_0
+{
+// in
+ char* message; // the message to display
+ eMessageType type;
+};
+
+// Data structure for service "EpgsearchMenu-v1.0"
+struct EpgSearchMenu_v1_0
+{
+// in
+// out
+ cOsdMenu* Menu; // pointer to the menu
+};
+
+// Data structure for service "Epgsearch-lastconflictinfo-v1.0"
+struct Epgsearch_lastconflictinfo_v1_0
+{
+// in
+// out
+ time_t nextConflict; // next conflict date, 0 if none
+ int relevantConflicts; // number of relevant conflicts
+ int totalConflicts; // total number of conflicts
+};
+
+// Data structure for service "Epgsearch-searchresults-v1.0"
+struct Epgsearch_searchresults_v1_0
+{
+// in
+ char* query; // search term
+ int mode; // search mode (0=phrase, 1=and, 2=or, 3=regular expression)
+ int channelNr; // channel number to search in (0=any)
+ bool useTitle; // search in title
+ bool useSubTitle; // search in subtitle
+ bool useDescription; // search in description
+// out
+
+ class cServiceSearchResult : public cListObject
+ {
+ public:
+ const cEvent* event;
+ cServiceSearchResult(const cEvent* Event) : event(Event) {}
+ };
+
+ cList<cServiceSearchResult>* pResultList; // pointer to the results
+};
+
+// Data structure for service "Epgsearch-switchtimer-v1.0"
+struct Epgsearch_switchtimer_v1_0
+{
+// in
+ const cEvent* event;
+ int mode; // mode (0=query existance, 1=add/modify, 2=delete)
+// in/out
+ int switchMinsBefore;
+ int announceOnly;
+// out
+ bool success; // result
+};
+
+// Data structures for service "Epgsearch-services-v1.0"
+class cServiceHandler
+{
+ public:
+ virtual std::list<std::string> SearchTimerList() = 0;
+ // returns a list of search timer entries in the same format as used in epgsearch.conf
+ virtual int AddSearchTimer(const std::string&) = 0;
+ // adds a new search timer and returns its ID (-1 on error)
+ virtual bool ModSearchTimer(const std::string&) = 0;
+ // edits an existing search timer and returns success
+ virtual bool DelSearchTimer(int) = 0;
+ // deletes search timer with given ID and returns success
+ virtual std::list<std::string> QuerySearchTimer(int) = 0;
+ // returns the search result of the searchtimer with given ID in the same format as used in SVDRP command 'QRYS' (->MANUAL)
+ virtual std::list<std::string> QuerySearch(std::string) = 0;
+ // returns the search result of the searchtimer with given settings in the same format as used in SVDRP command 'QRYS' (->MANUAL)
+ virtual std::list<std::string> ExtEPGInfoList() = 0;
+ // returns a list of extended EPG categories in the same format as used in epgsearchcats.conf
+ virtual std::list<std::string> ChanGrpList() = 0;
+ // returns a list of channel groups maintained by epgsearch
+ virtual std::list<std::string> BlackList() = 0;
+ // returns a list of blacklists in the same format as used in epgsearchblacklists.conf
+ virtual std::set<std::string> DirectoryList() = 0;
+ // List of all recording directories used in recordings, timers, search timers or in epgsearchdirs.conf
+ virtual ~cServiceHandler() {}
+ // Read a setup value
+ virtual std::string ReadSetupValue(const std::string& entry) = 0;
+ // Write a setup value
+ virtual bool WriteSetupValue(const std::string& entry, const std::string& value) = 0;
+};
+
+struct Epgsearch_services_v1_0
+{
+// in/out
+ std::auto_ptr<cServiceHandler> handler;
+};
+
+#endif
diff --git a/services/remotetimers.h b/services/remotetimers.h
new file mode 100644
index 0000000..2dc8a97
--- /dev/null
+++ b/services/remotetimers.h
@@ -0,0 +1,141 @@
+/*
+ * remotetimers.h: Public interface of the plugin's services
+ *
+ * Copyright (C) 2008-2011 Frank Schmirler <vdr@schmirler.de>
+ *
+ * This file is part of VDR Plugin remotetimers.
+ *
+ * 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
+ * of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ */
+
+#ifndef _SERVICE__H
+#define _SERVICE__H
+
+#ifndef __TIMERS_H
+#include <vdr/timers.h>
+#include <vdr/epg.h>
+#endif
+
+/*
+ * If the Data argument is NULL, all service calls return true.
+ * Otherwise the return value indicates success or failure of the service call.
+ *
+ * The service calls are not thread safe and must be called from the VDR main loop.
+ */
+
+/*
+ * RemoteTimers::InstantRecording-v1.0
+ * Start an instant recording or pause live TV. VDR needs to be patched to support this.
+ * The service returns false if a local timer should be used. An error occured if true is returned but the out parameters name and fileName are NULL.
+ * Data points to the following structure where pause indicates if it is an instant recording or an attempt to pause live TV.
+ */
+
+struct RemoteTimers_InstantRecording_v1_0 {
+//in
+ const cTimer *timer;
+ bool pause;
+ const cEvent *event;
+//out
+ cString name;
+ cString fileName;
+};
+
+/*
+ * RemoteTimers::RefreshTimers-v1.0
+ * Fetch timer list from remote VDR. You must call this service before you can use one of the service calls below.
+ * Data points to a cString which in case of failure (service call returns false) contains an error message.
+ */
+
+//out
+// cString errorMsg;
+
+/*
+ * RemoteTimers::ForEach-v1.0
+ * Iterates the list of remote timers.
+ * The service call always returns true.
+ * Data points to a cTimer* which must be NULL to return the first timer. Pass the previously returned timer to get the next one until cTimer* is NULL.
+ *
+ * RemoteTimers::GetTimer-v1.0
+ * Test if the timer exists as either a remote or a local timer.
+ * The service call always returns true.
+ * Data points to a cTimer* which points to the timer you are looking for. If found, cTimer* will point to the timer, otherwise it will be NULL.
+ */
+
+//in+out
+// cTimer* timer;
+
+/*
+ * RemoteTimers::GetMatch-v1.0
+ * Find the remote or local timer which matches the event best.
+ * The service call always returns true.
+ * Data points to the following structure:
+ */
+
+struct RemoteTimers_GetMatch_v1_0 {
+//in
+ const cEvent *event;
+//out
+ cTimer *timer;
+ int timerMatch;
+ int timerType;
+ bool isRemote;
+};
+
+/*
+ * RemoteTimers::GetTimerByEvent-v1.0
+ * Find the remote or local timer matching the event.
+ * If no timer matches, the service call returns false.
+ * Data points to a RemoteTimers_Event_v1_0 struct.
+ *
+ * RemoteTimers::NewTimerByEvent-v1.0
+ * Add a new timer for an event.
+ * In case of an error, the service call returns false and the structure includes an error message.
+ * Data points to a RemoteTimers_Event_v1_0 struct.
+ */
+
+struct RemoteTimers_Event_v1_0 {
+//in
+ const cEvent *event;
+//out
+ cTimer *timer;
+ cString errorMsg;
+};
+
+/*
+ * RemoteTimers::NewTimer-v1.0
+ * Add a new timer.
+ * In case of an error, the service call returns false and the structure includes an error message.
+ * Data points to a RemoteTimers_Timer_v1_0 struct.
+ *
+ * RemoteTimers::ModTimer-v1.0
+ * Change an existing timer.
+ * In case of an error, the service call returns false and the structure includes an error message.
+ * Data points to a RemoteTimers_Timer_v1_0 struct.
+ *
+ * RemoteTimers::DelTimer-v1.0
+ * Delete an existing timer.
+ * In case of an error, the service call returns false and the structure includes an error message.
+ * Data points to a RemoteTimers_Timer_v1_0 struct.
+ */
+
+struct RemoteTimers_Timer_v1_0 {
+//in+out
+ cTimer *timer;
+//out
+ cString errorMsg;
+};
+
+#endif //_SERVICE__H
diff --git a/services/scraper2vdr.h b/services/scraper2vdr.h
new file mode 100644
index 0000000..a5d6043
--- /dev/null
+++ b/services/scraper2vdr.h
@@ -0,0 +1,214 @@
+#ifndef __SCRAPER2VDRSERVICES_H
+#define __SCRAPER2VDRSERVICES_H
+
+#include <string>
+#include <vector>
+#include <vdr/epg.h>
+#include <vdr/recording.h>
+
+enum tvType {
+ tSeries,
+ tMovie,
+ tNone,
+};
+
+/*********************************************************************
+* Helper Structures
+*********************************************************************/
+class cTvMedia {
+public:
+ cTvMedia(void) {
+ path = "";
+ width = height = 0;
+ };
+ std::string path;
+ int width;
+ int height;
+};
+
+class cEpisode {
+public:
+ cEpisode(void) {
+ number = 0;
+ season = 0;
+ name = "";
+ firstAired = "";
+ guestStars = "";
+ overview = "";
+ rating = 0.0;
+ };
+ int number;
+ int season;
+ std::string name;
+ std::string firstAired;
+ std::string guestStars;
+ std::string overview;
+ float rating;
+ cTvMedia episodeImage;
+};
+
+class cActor {
+public:
+ cActor(void) {
+ name = "";
+ role = "";
+ };
+ std::string name;
+ std::string role;
+ cTvMedia actorThumb;
+};
+
+/*********************************************************************
+* Data Structures for Service Calls
+*********************************************************************/
+
+// Data structure for service "GetEventType"
+class ScraperGetEventType {
+public:
+ ScraperGetEventType(void) {
+ event = NULL;
+ recording = NULL;
+ type = tNone;
+ movieId = 0;
+ seriesId = 0;
+ episodeId = 0;
+ };
+// in
+ const cEvent *event; // check type for this event
+ const cRecording *recording; // or for this recording
+//out
+ tvType type; //typeSeries or typeMovie
+ int movieId;
+ int seriesId;
+ int episodeId;
+};
+
+//Data structure for full series and episode information
+class cMovie {
+public:
+ cMovie(void) {
+ title = "";
+ originalTitle = "";
+ tagline = "";
+ overview = "";
+ adult = false;
+ collectionName = "";
+ budget = 0;
+ revenue = 0;
+ genres = "";
+ homepage = "";
+ releaseDate = "";
+ runtime = 0;
+ popularity = 0.0;
+ voteAverage = 0.0;
+ };
+//IN
+ int movieId; // movieId fetched from ScraperGetEventType
+//OUT
+ std::string title;
+ std::string originalTitle;
+ std::string tagline;
+ std::string overview;
+ bool adult;
+ std::string collectionName;
+ int budget;
+ int revenue;
+ std::string genres;
+ std::string homepage;
+ std::string releaseDate;
+ int runtime;
+ float popularity;
+ float voteAverage;
+ cTvMedia poster;
+ cTvMedia fanart;
+ cTvMedia collectionPoster;
+ cTvMedia collectionFanart;
+ std::vector<cActor> actors;
+};
+
+//Data structure for full series and episode information
+class cSeries {
+public:
+ cSeries(void) {
+ seriesId = 0;
+ episodeId = 0;
+ name = "";
+ overview = "";
+ firstAired = "";
+ network = "";
+ genre = "";
+ rating = 0.0;
+ status = "";
+ };
+//IN
+ int seriesId; // seriesId fetched from ScraperGetEventType
+ int episodeId; // episodeId fetched from ScraperGetEventType
+//OUT
+ std::string name;
+ std::string overview;
+ std::string firstAired;
+ std::string network;
+ std::string genre;
+ float rating;
+ std::string status;
+ cEpisode episode;
+ std::vector<cActor> actors;
+ std::vector<cTvMedia> posters;
+ std::vector<cTvMedia> banners;
+ std::vector<cTvMedia> fanarts;
+ cTvMedia seasonPoster;
+};
+
+// Data structure for service "GetPosterBanner"
+class ScraperGetPosterBanner {
+public:
+ ScraperGetPosterBanner(void) {
+ type = tNone;
+ event = NULL;
+ };
+// in
+ const cEvent *event; // check type for this event
+//out
+ tvType type; //typeSeries or typeMovie
+ cTvMedia poster;
+ cTvMedia banner;
+};
+
+// Data structure for service "GetPosterBannerV2"
+class ScraperGetPosterBannerV2 {
+public:
+ ScraperGetPosterBannerV2(void) {
+ type = tNone;
+ event = NULL;
+ recording = NULL;
+ };
+// in
+ const cEvent *event; // check type for this event
+ const cRecording *recording; // check type for this recording
+//out
+ tvType type; //typeSeries or typeMovie
+ cTvMedia poster;
+ cTvMedia banner;
+};
+
+// Data structure for service "GetPoster"
+class ScraperGetPoster {
+public:
+// in
+ const cEvent *event; // check type for this event
+ const cRecording *recording; // or for this recording
+//out
+ cTvMedia poster;
+};
+
+// Data structure for service "GetPosterThumb"
+class ScraperGetPosterThumb {
+public:
+// in
+ const cEvent *event; // check type for this event
+ const cRecording *recording; // or for this recording
+//out
+ cTvMedia poster;
+};
+
+#endif //__SCRAPER2VDRSERVICES_H \ No newline at end of file
diff --git a/setup.c b/setup.c
new file mode 100644
index 0000000..0b85782
--- /dev/null
+++ b/setup.c
@@ -0,0 +1,73 @@
+#include "setup.h"
+
+cSkinDesignerSetup::cSkinDesignerSetup() {
+ data = config;
+ Setup();
+}
+
+cSkinDesignerSetup::~cSkinDesignerSetup() {
+}
+
+
+void cSkinDesignerSetup::Setup(void) {
+ int current = Current();
+ Clear();
+
+ Add(new cMenuEditBoolItem(tr("Debug Image Loading"), &data.debugImageLoading));
+
+ Add(new cMenuEditBoolItem(tr("Limit Channel Logo Cache"), &data.limitLogoCache));
+ Add(new cMenuEditIntItem(tr("Number to cache initially (per size)"), &data.numLogosPerSizeInitial, 0, 1000));
+ Add(new cMenuEditIntItem(tr("Number to cache in maximum"), &data.numLogosMax, 0, 1000));
+
+ cString message = cString::sprintf("--------------------- %s ---------------------", tr("Cache Statistics"));
+ Add(new cOsdItem(*message));
+ cList<cOsdItem>::Last()->SetSelectable(false);
+
+ int sizeIconCache = 0;
+ int numIcons = 0;
+ imgCache->GetIconCacheSize(numIcons, sizeIconCache);
+ cString iconCacheInfo = cString::sprintf("%s %d %s - %s %d %s", tr("cached"), numIcons, tr("icons"), tr("size"), sizeIconCache, tr("byte"));
+ Add(new cOsdItem(*iconCacheInfo));
+ cList<cOsdItem>::Last()->SetSelectable(false);
+
+ int sizeLogoCache = 0;
+ int numLogos = 0;
+ imgCache->GetLogoCacheSize(numLogos, sizeLogoCache);
+ cString logoCacheInfo = cString::sprintf("%s %d %s - %s %d %s", tr("cached"), numLogos, tr("logos"), tr("size"), sizeLogoCache, tr("byte"));
+ Add(new cOsdItem(*logoCacheInfo));
+ cList<cOsdItem>::Last()->SetSelectable(false);
+
+ int sizeSkinpartCache = 0;
+ int numSkinparts = 0;
+ imgCache->GetSkinpartsCacheSize(numSkinparts, sizeSkinpartCache);
+ cString skinpartCacheInfo = cString::sprintf("%s %d %s - %s %d %s", tr("cached"), numSkinparts, tr("skinparts"), tr("size"), sizeSkinpartCache, tr("byte"));
+ Add(new cOsdItem(*skinpartCacheInfo));
+ cList<cOsdItem>::Last()->SetSelectable(false);
+
+ SetCurrent(Get(current));
+ Display();
+}
+
+eOSState cSkinDesignerSetup::ProcessKey(eKeys Key) {
+ eOSState state = cMenuSetupPage::ProcessKey(Key);
+ switch (state) {
+ case osContinue: {
+ if (NORMALKEY(Key) == kUp || NORMALKEY(Key) == kDown) {
+ cOsdItem* item = Get(Current());
+ if (item)
+ item->ProcessKey(kNone);
+ }
+ break; }
+ default: break;
+ }
+ return state;
+}
+
+void cSkinDesignerSetup::Store(void) {
+ config = data;
+
+ SetupStore("DebugImageLoading", config.debugImageLoading);
+ SetupStore("LimitChannelLogoCache", config.limitLogoCache);
+ SetupStore("NumberLogosInitially", config.numLogosPerSizeInitial);
+ SetupStore("NumberLogosMax", config.numLogosMax);
+} \ No newline at end of file
diff --git a/setup.h b/setup.h
new file mode 100644
index 0000000..ea9bf13
--- /dev/null
+++ b/setup.h
@@ -0,0 +1,16 @@
+#ifndef __SKINDESIGNER_SETUP_H
+#define __SKINDESIGNER_SETUP_H
+
+#include "config.h"
+
+class cSkinDesignerSetup : public cMenuSetupPage {
+ public:
+ cSkinDesignerSetup(void);
+ virtual ~cSkinDesignerSetup();
+ private:
+ cDesignerConfig data;
+ void Setup(void);
+ virtual eOSState ProcessKey(eKeys Key);
+ virtual void Store(void);
+};
+#endif //__SKINDESIGNER_SETUP_H \ No newline at end of file
diff --git a/skindesigner.c b/skindesigner.c
new file mode 100644
index 0000000..5074c9d
--- /dev/null
+++ b/skindesigner.c
@@ -0,0 +1,165 @@
+/*
+ * skindesigner.c: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+#include <getopt.h>
+#include <vdr/plugin.h>
+#include <vdr/skinlcars.h>
+
+#define DEFINE_CONFIG 1
+#include "config.h"
+#include "designer.h"
+#include "setup.h"
+
+
+#if defined(APIVERSNUM) && APIVERSNUM < 20000
+#error "VDR-2.0.0 API version or greater is required!"
+#endif
+
+
+static const char *VERSION = "0.0.1";
+static const char *DESCRIPTION = "SkinDesigner";
+static const char *MAINMENUENTRY = "Skin Designer";
+
+class cPluginSkinDesigner : public cPlugin {
+private:
+ cSkinDesigner *skinDesigner;
+public:
+ cPluginSkinDesigner(void);
+ virtual ~cPluginSkinDesigner();
+ virtual const char *Version(void) { return VERSION; }
+ virtual const char *Description(void) { return DESCRIPTION; }
+ virtual const char *CommandLineHelp(void);
+ virtual bool ProcessArgs(int argc, char *argv[]);
+ virtual bool Initialize(void);
+ virtual bool Start(void);
+ virtual void Stop(void);
+ virtual void Housekeeping(void);
+ virtual void MainThreadHook(void);
+ virtual cString Active(void);
+ virtual time_t WakeupTime(void);
+ virtual const char *MainMenuEntry(void) {return NULL;}
+ virtual cOsdObject *MainMenuAction(void);
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+ virtual bool Service(const char *Id, void *Data = NULL);
+ virtual const char **SVDRPHelpPages(void);
+ virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
+};
+
+cPluginSkinDesigner::cPluginSkinDesigner(void) {
+ skinDesigner = NULL;
+}
+
+cPluginSkinDesigner::~cPluginSkinDesigner() {
+}
+
+const char *cPluginSkinDesigner::CommandLineHelp(void) {
+ return
+ " -s <SKINPATH>, --skinpath=<SKINPATH> Set directory where xml skins are stored\n"
+ " -e <EPGIMAGESPATH>, --epgimages=<IMAGESPATH> Set directory where epgimages are stored\n";
+}
+
+bool cPluginSkinDesigner::ProcessArgs(int argc, char *argv[]) {
+ // Implement command line argument processing here if applicable.
+ static const struct option long_options[] = {
+ { "epgimages", required_argument, NULL, 'e' },
+ { "skinpath", required_argument, NULL, 's' },
+ { 0, 0, 0, 0 }
+ };
+
+ int c;
+ while ((c = getopt_long(argc, argv, "e:s:", long_options, NULL)) != -1) {
+ switch (c) {
+ case 'e':
+ config.SetEpgImagePath(cString(optarg));
+ break;
+ case 's':
+ config.SetSkinPath(cString(optarg));
+ break;
+ default:
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cPluginSkinDesigner::Initialize(void) {
+ return true;
+}
+
+bool cPluginSkinDesigner::Start(void) {
+ if (!cOsdProvider::SupportsTrueColor()) {
+ esyslog("skinDesigner: No TrueColor OSD found! Using default Skin LCARS!");
+ return new cSkinLCARS();
+ } else
+ dsyslog("skinDesigner: TrueColor OSD found");
+ skinDesigner = new cSkinDesigner();
+ return skinDesigner;
+}
+
+void cPluginSkinDesigner::Stop(void) {
+ delete imgCache;
+ delete fontManager;
+}
+
+void cPluginSkinDesigner::Housekeeping(void) {
+}
+
+void cPluginSkinDesigner::MainThreadHook(void) {
+}
+
+cString cPluginSkinDesigner::Active(void) {
+ return NULL;
+}
+
+time_t cPluginSkinDesigner::WakeupTime(void) {
+ return 0;
+}
+
+cOsdObject *cPluginSkinDesigner::MainMenuAction(void) {
+ return NULL;
+}
+
+cMenuSetupPage *cPluginSkinDesigner::SetupMenu(void) {
+ return new cSkinDesignerSetup();
+}
+
+bool cPluginSkinDesigner::SetupParse(const char *Name, const char *Value) {
+ return config.SetupParse(Name, Value);
+}
+
+bool cPluginSkinDesigner::Service(const char *Id, void *Data) {
+ return false;
+}
+
+const char **cPluginSkinDesigner::SVDRPHelpPages(void) {
+ static const char *HelpPages[] = {
+ "RELD\n"
+ " force reload of templates and caches",
+ "LSTF\n"
+ " List available Fonts",
+ 0
+ };
+ return HelpPages;
+}
+
+cString cPluginSkinDesigner::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) {
+ if (strcasecmp(Command, "RELD") == 0) {
+ if (skinDesigner) {
+ skinDesigner->Reload();
+ return "SKINDESIGNER reload of templates and caches forced.";
+ }
+ } else if (strcasecmp(Command, "LSTF") == 0) {
+ if (skinDesigner) {
+ skinDesigner->ListAvailableFonts();
+ return "SKINDESIGNER available fonts listed in syslog.";
+ }
+ }
+ return NULL;
+}
+
+VDRPLUGINCREATOR(cPluginSkinDesigner); // Don't touch this!
diff --git a/skins/default/graphics/icons/ico_ac3.png b/skins/default/graphics/icons/ico_ac3.png
new file mode 100644
index 0000000..5b8614a
--- /dev/null
+++ b/skins/default/graphics/icons/ico_ac3.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_activetimer.png b/skins/default/graphics/icons/ico_activetimer.png
new file mode 100644
index 0000000..af4c33c
--- /dev/null
+++ b/skins/default/graphics/icons/ico_activetimer.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_channelsep.png b/skins/default/graphics/icons/ico_channelsep.png
new file mode 100644
index 0000000..bf51238
--- /dev/null
+++ b/skins/default/graphics/icons/ico_channelsep.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_crypt_off.png b/skins/default/graphics/icons/ico_crypt_off.png
new file mode 100644
index 0000000..b612aec
--- /dev/null
+++ b/skins/default/graphics/icons/ico_crypt_off.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_crypt_on.png b/skins/default/graphics/icons/ico_crypt_on.png
new file mode 100644
index 0000000..55abed4
--- /dev/null
+++ b/skins/default/graphics/icons/ico_crypt_on.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_cutted.png b/skins/default/graphics/icons/ico_cutted.png
new file mode 100644
index 0000000..b90c9c1
--- /dev/null
+++ b/skins/default/graphics/icons/ico_cutted.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_discusage.png b/skins/default/graphics/icons/ico_discusage.png
new file mode 100644
index 0000000..f40fcd9
--- /dev/null
+++ b/skins/default/graphics/icons/ico_discusage.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_dolby_off.png b/skins/default/graphics/icons/ico_dolby_off.png
new file mode 100644
index 0000000..17815f5
--- /dev/null
+++ b/skins/default/graphics/icons/ico_dolby_off.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_dolby_on.png b/skins/default/graphics/icons/ico_dolby_on.png
new file mode 100644
index 0000000..c06c18e
--- /dev/null
+++ b/skins/default/graphics/icons/ico_dolby_on.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_ff.png b/skins/default/graphics/icons/ico_ff.png
new file mode 100644
index 0000000..5ffbe4b
--- /dev/null
+++ b/skins/default/graphics/icons/ico_ff.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_ff_1x.png b/skins/default/graphics/icons/ico_ff_1x.png
new file mode 100644
index 0000000..96a74bc
--- /dev/null
+++ b/skins/default/graphics/icons/ico_ff_1x.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_ff_2x.png b/skins/default/graphics/icons/ico_ff_2x.png
new file mode 100644
index 0000000..54657bf
--- /dev/null
+++ b/skins/default/graphics/icons/ico_ff_2x.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_ff_3x.png b/skins/default/graphics/icons/ico_ff_3x.png
new file mode 100644
index 0000000..ac21eca
--- /dev/null
+++ b/skins/default/graphics/icons/ico_ff_3x.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_ff_off.png b/skins/default/graphics/icons/ico_ff_off.png
new file mode 100644
index 0000000..5a9ab50
--- /dev/null
+++ b/skins/default/graphics/icons/ico_ff_off.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_hd_off.png b/skins/default/graphics/icons/ico_hd_off.png
new file mode 100644
index 0000000..cd0492a
--- /dev/null
+++ b/skins/default/graphics/icons/ico_hd_off.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_hd_on.png b/skins/default/graphics/icons/ico_hd_on.png
new file mode 100644
index 0000000..5f6cfa5
--- /dev/null
+++ b/skins/default/graphics/icons/ico_hd_on.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_line_off.png b/skins/default/graphics/icons/ico_line_off.png
new file mode 100644
index 0000000..94591ee
--- /dev/null
+++ b/skins/default/graphics/icons/ico_line_off.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_line_on.png b/skins/default/graphics/icons/ico_line_on.png
new file mode 100644
index 0000000..1584078
--- /dev/null
+++ b/skins/default/graphics/icons/ico_line_on.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_mute.png b/skins/default/graphics/icons/ico_mute.png
new file mode 100644
index 0000000..4eefc75
--- /dev/null
+++ b/skins/default/graphics/icons/ico_mute.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_pause.png b/skins/default/graphics/icons/ico_pause.png
new file mode 100644
index 0000000..405a097
--- /dev/null
+++ b/skins/default/graphics/icons/ico_pause.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_pause_off.png b/skins/default/graphics/icons/ico_pause_off.png
new file mode 100644
index 0000000..6f02e39
--- /dev/null
+++ b/skins/default/graphics/icons/ico_pause_off.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_play.png b/skins/default/graphics/icons/ico_play.png
new file mode 100644
index 0000000..02a01c0
--- /dev/null
+++ b/skins/default/graphics/icons/ico_play.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_play_off.png b/skins/default/graphics/icons/ico_play_off.png
new file mode 100644
index 0000000..d87322a
--- /dev/null
+++ b/skins/default/graphics/icons/ico_play_off.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_rec_off.png b/skins/default/graphics/icons/ico_rec_off.png
new file mode 100644
index 0000000..224baea
--- /dev/null
+++ b/skins/default/graphics/icons/ico_rec_off.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_rec_on.png b/skins/default/graphics/icons/ico_rec_on.png
new file mode 100644
index 0000000..7bc18a7
--- /dev/null
+++ b/skins/default/graphics/icons/ico_rec_on.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_recfolder.png b/skins/default/graphics/icons/ico_recfolder.png
new file mode 100644
index 0000000..e3df65b
--- /dev/null
+++ b/skins/default/graphics/icons/ico_recfolder.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_recnew.png b/skins/default/graphics/icons/ico_recnew.png
new file mode 100644
index 0000000..b9166ba
--- /dev/null
+++ b/skins/default/graphics/icons/ico_recnew.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_rew.png b/skins/default/graphics/icons/ico_rew.png
new file mode 100644
index 0000000..1505f79
--- /dev/null
+++ b/skins/default/graphics/icons/ico_rew.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_rew_1x.png b/skins/default/graphics/icons/ico_rew_1x.png
new file mode 100644
index 0000000..6ddbde4
--- /dev/null
+++ b/skins/default/graphics/icons/ico_rew_1x.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_rew_2x.png b/skins/default/graphics/icons/ico_rew_2x.png
new file mode 100644
index 0000000..9b7ee52
--- /dev/null
+++ b/skins/default/graphics/icons/ico_rew_2x.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_rew_3x.png b/skins/default/graphics/icons/ico_rew_3x.png
new file mode 100644
index 0000000..4a3abeb
--- /dev/null
+++ b/skins/default/graphics/icons/ico_rew_3x.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_rew_off.png b/skins/default/graphics/icons/ico_rew_off.png
new file mode 100644
index 0000000..a84a7f3
--- /dev/null
+++ b/skins/default/graphics/icons/ico_rew_off.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_stereo.png b/skins/default/graphics/icons/ico_stereo.png
new file mode 100644
index 0000000..7f3610d
--- /dev/null
+++ b/skins/default/graphics/icons/ico_stereo.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_timer_active.png b/skins/default/graphics/icons/ico_timer_active.png
new file mode 100644
index 0000000..28c2f81
--- /dev/null
+++ b/skins/default/graphics/icons/ico_timer_active.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_timer_inactive.png b/skins/default/graphics/icons/ico_timer_inactive.png
new file mode 100644
index 0000000..c4b1860
--- /dev/null
+++ b/skins/default/graphics/icons/ico_timer_inactive.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_timer_recording.png b/skins/default/graphics/icons/ico_timer_recording.png
new file mode 100644
index 0000000..86dc66b
--- /dev/null
+++ b/skins/default/graphics/icons/ico_timer_recording.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_txt_off.png b/skins/default/graphics/icons/ico_txt_off.png
new file mode 100644
index 0000000..a445bc5
--- /dev/null
+++ b/skins/default/graphics/icons/ico_txt_off.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_txt_on.png b/skins/default/graphics/icons/ico_txt_on.png
new file mode 100644
index 0000000..ad14ff7
--- /dev/null
+++ b/skins/default/graphics/icons/ico_txt_on.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_volume.png b/skins/default/graphics/icons/ico_volume.png
new file mode 100644
index 0000000..3a72514
--- /dev/null
+++ b/skins/default/graphics/icons/ico_volume.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_widescreen_off.png b/skins/default/graphics/icons/ico_widescreen_off.png
new file mode 100644
index 0000000..dffd6a5
--- /dev/null
+++ b/skins/default/graphics/icons/ico_widescreen_off.png
Binary files differ
diff --git a/skins/default/graphics/icons/ico_widescreen_on.png b/skins/default/graphics/icons/ico_widescreen_on.png
new file mode 100644
index 0000000..876bb55
--- /dev/null
+++ b/skins/default/graphics/icons/ico_widescreen_on.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Applikationen.png b/skins/default/graphics/menuicons/customicons/Applikationen.png
new file mode 100644
index 0000000..3c3b616
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Applikationen.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Audio.png b/skins/default/graphics/menuicons/customicons/Audio.png
new file mode 100644
index 0000000..ff387fe
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Audio.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Aufnahmen-Liste aktualisieren.png b/skins/default/graphics/menuicons/customicons/Aufnahmen-Liste aktualisieren.png
new file mode 100644
index 0000000..3cdddc9
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Aufnahmen-Liste aktualisieren.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Dienstprogramme.png b/skins/default/graphics/menuicons/customicons/Dienstprogramme.png
new file mode 100644
index 0000000..793aba6
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Dienstprogramme.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/FireFox.png b/skins/default/graphics/menuicons/customicons/FireFox.png
new file mode 100644
index 0000000..192fadc
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/FireFox.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Info.png b/skins/default/graphics/menuicons/customicons/Info.png
new file mode 100644
index 0000000..6737431
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Info.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Internet.png b/skins/default/graphics/menuicons/customicons/Internet.png
new file mode 100644
index 0000000..f3db150
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Internet.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Medien.png b/skins/default/graphics/menuicons/customicons/Medien.png
new file mode 100644
index 0000000..0ce2360
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Medien.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Rechner neu starten.png b/skins/default/graphics/menuicons/customicons/Rechner neu starten.png
new file mode 100644
index 0000000..5783ccf
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Rechner neu starten.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Remote wakeup.png b/skins/default/graphics/menuicons/customicons/Remote wakeup.png
new file mode 100644
index 0000000..1cd2f6e
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Remote wakeup.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Spiele.png b/skins/default/graphics/menuicons/customicons/Spiele.png
new file mode 100644
index 0000000..8e07161
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Spiele.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/System herunterfahren.png b/skins/default/graphics/menuicons/customicons/System herunterfahren.png
new file mode 100644
index 0000000..e0234df
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/System herunterfahren.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/System.png b/skins/default/graphics/menuicons/customicons/System.png
new file mode 100644
index 0000000..81d100e
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/System.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Tools.png b/skins/default/graphics/menuicons/customicons/Tools.png
new file mode 100644
index 0000000..cf328ef
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Tools.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Tunderbird.png b/skins/default/graphics/menuicons/customicons/Tunderbird.png
new file mode 100644
index 0000000..5ae27e0
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Tunderbird.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/USB Massenspeicher sicher entfernen.png b/skins/default/graphics/menuicons/customicons/USB Massenspeicher sicher entfernen.png
new file mode 100644
index 0000000..cd7b81c
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/USB Massenspeicher sicher entfernen.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/VDR neu starten.png b/skins/default/graphics/menuicons/customicons/VDR neu starten.png
new file mode 100644
index 0000000..14904ca
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/VDR neu starten.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Video.png b/skins/default/graphics/menuicons/customicons/Video.png
new file mode 100644
index 0000000..490ca4b
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Video.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Web.png b/skins/default/graphics/menuicons/customicons/Web.png
new file mode 100644
index 0000000..20260e3
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Web.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/XBMC.png b/skins/default/graphics/menuicons/customicons/XBMC.png
new file mode 100644
index 0000000..c7c4c04
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/XBMC.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/Xterm.png b/skins/default/graphics/menuicons/customicons/Xterm.png
new file mode 100644
index 0000000..fa75282
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/Xterm.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/audiovideo.png b/skins/default/graphics/menuicons/customicons/audiovideo.png
new file mode 100644
index 0000000..726538d
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/audiovideo.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/markad_status.png b/skins/default/graphics/menuicons/customicons/markad_status.png
new file mode 100644
index 0000000..4fdc7a4
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/markad_status.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/schneiden_abbrechen.png b/skins/default/graphics/menuicons/customicons/schneiden_abbrechen.png
new file mode 100644
index 0000000..b2e0bd3
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/schneiden_abbrechen.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/tux.png b/skins/default/graphics/menuicons/customicons/tux.png
new file mode 100644
index 0000000..c5b4742
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/tux.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/usb.png b/skins/default/graphics/menuicons/customicons/usb.png
new file mode 100644
index 0000000..c4db1d4
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/usb.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/vdrlogo.png b/skins/default/graphics/menuicons/customicons/vdrlogo.png
new file mode 100644
index 0000000..037a191
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/vdrlogo.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/customicons/yaicon_blue.png b/skins/default/graphics/menuicons/customicons/yaicon_blue.png
new file mode 100644
index 0000000..2c49273
--- /dev/null
+++ b/skins/default/graphics/menuicons/customicons/yaicon_blue.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/admin.png b/skins/default/graphics/menuicons/pluginicons/admin.png
new file mode 100644
index 0000000..cf328ef
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/admin.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/arghdirector.png b/skins/default/graphics/menuicons/pluginicons/arghdirector.png
new file mode 100644
index 0000000..bbd221a
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/arghdirector.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/autostart.png b/skins/default/graphics/menuicons/pluginicons/autostart.png
new file mode 100644
index 0000000..6fdb1bb
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/autostart.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/avahi4vdr.png b/skins/default/graphics/menuicons/pluginicons/avahi4vdr.png
new file mode 100644
index 0000000..044e71d
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/avahi4vdr.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/avards.png b/skins/default/graphics/menuicons/pluginicons/avards.png
new file mode 100644
index 0000000..cf8d037
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/avards.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/block.png b/skins/default/graphics/menuicons/pluginicons/block.png
new file mode 100644
index 0000000..86127c2
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/block.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/burn.png b/skins/default/graphics/menuicons/pluginicons/burn.png
new file mode 100644
index 0000000..305d7ff
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/burn.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/cdplayer.png b/skins/default/graphics/menuicons/pluginicons/cdplayer.png
new file mode 100644
index 0000000..89a6c19
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/cdplayer.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/chanman.png b/skins/default/graphics/menuicons/pluginicons/chanman.png
new file mode 100644
index 0000000..a73e83c
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/chanman.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/check.png b/skins/default/graphics/menuicons/pluginicons/check.png
new file mode 100644
index 0000000..d487a24
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/check.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/conflictcheckonly.png b/skins/default/graphics/menuicons/pluginicons/conflictcheckonly.png
new file mode 100644
index 0000000..7f832bd
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/conflictcheckonly.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/ddci.png b/skins/default/graphics/menuicons/pluginicons/ddci.png
new file mode 100644
index 0000000..4ad459c
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/ddci.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/devstatus.png b/skins/default/graphics/menuicons/pluginicons/devstatus.png
new file mode 100644
index 0000000..96c0ec1
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/devstatus.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/dummydevice.png b/skins/default/graphics/menuicons/pluginicons/dummydevice.png
new file mode 100644
index 0000000..11fd707
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/dummydevice.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/duplicates.png b/skins/default/graphics/menuicons/pluginicons/duplicates.png
new file mode 100644
index 0000000..dc1be57
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/duplicates.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/dvbapi.png b/skins/default/graphics/menuicons/pluginicons/dvbapi.png
new file mode 100644
index 0000000..b966461
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/dvbapi.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/dvbhddevice.png b/skins/default/graphics/menuicons/pluginicons/dvbhddevice.png
new file mode 100644
index 0000000..b874297
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/dvbhddevice.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/dvbsddevice.png b/skins/default/graphics/menuicons/pluginicons/dvbsddevice.png
new file mode 100644
index 0000000..106184e
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/dvbsddevice.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/dynamite.png b/skins/default/graphics/menuicons/pluginicons/dynamite.png
new file mode 100644
index 0000000..28ea35a
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/dynamite.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/eepg.png b/skins/default/graphics/menuicons/pluginicons/eepg.png
new file mode 100644
index 0000000..3938b96
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/eepg.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/epg2vdr.png b/skins/default/graphics/menuicons/pluginicons/epg2vdr.png
new file mode 100644
index 0000000..ac8757e
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/epg2vdr.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/epgsearch.png b/skins/default/graphics/menuicons/pluginicons/epgsearch.png
new file mode 100644
index 0000000..5eab415
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/epgsearch.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/epgsearchonly.png b/skins/default/graphics/menuicons/pluginicons/epgsearchonly.png
new file mode 100644
index 0000000..b5186e7
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/epgsearchonly.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/epgsync.png b/skins/default/graphics/menuicons/pluginicons/epgsync.png
new file mode 100644
index 0000000..5c14009
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/epgsync.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/externalplayer.png b/skins/default/graphics/menuicons/pluginicons/externalplayer.png
new file mode 100644
index 0000000..2bd67db
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/externalplayer.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/extrecmenu.png b/skins/default/graphics/menuicons/pluginicons/extrecmenu.png
new file mode 100644
index 0000000..6f613f1
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/extrecmenu.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/favorites.png b/skins/default/graphics/menuicons/pluginicons/favorites.png
new file mode 100644
index 0000000..409c852
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/favorites.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/femon.png b/skins/default/graphics/menuicons/pluginicons/femon.png
new file mode 100644
index 0000000..e87b711
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/femon.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/fepg.png b/skins/default/graphics/menuicons/pluginicons/fepg.png
new file mode 100644
index 0000000..65023ed
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/fepg.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/filebrowser.png b/skins/default/graphics/menuicons/pluginicons/filebrowser.png
new file mode 100644
index 0000000..d3f90e0
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/filebrowser.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/fritzbox.png b/skins/default/graphics/menuicons/pluginicons/fritzbox.png
new file mode 100644
index 0000000..7bfc229
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/fritzbox.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/graphlcd.png b/skins/default/graphics/menuicons/pluginicons/graphlcd.png
new file mode 100644
index 0000000..39ffd35
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/graphlcd.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/graphtft.png b/skins/default/graphics/menuicons/pluginicons/graphtft.png
new file mode 100644
index 0000000..39ffd35
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/graphtft.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/image.png b/skins/default/graphics/menuicons/pluginicons/image.png
new file mode 100644
index 0000000..33644e0
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/image.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/imonlcd.png b/skins/default/graphics/menuicons/pluginicons/imonlcd.png
new file mode 100644
index 0000000..3d34fc4
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/imonlcd.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/iptv.png b/skins/default/graphics/menuicons/pluginicons/iptv.png
new file mode 100644
index 0000000..4494ddc
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/iptv.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/lcdproc.png b/skins/default/graphics/menuicons/pluginicons/lcdproc.png
new file mode 100644
index 0000000..3d34fc4
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/lcdproc.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/mailbox.png b/skins/default/graphics/menuicons/pluginicons/mailbox.png
new file mode 100644
index 0000000..1bc76e8
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/mailbox.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/makemkv.png b/skins/default/graphics/menuicons/pluginicons/makemkv.png
new file mode 100644
index 0000000..41cddf1
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/makemkv.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/markad.png b/skins/default/graphics/menuicons/pluginicons/markad.png
new file mode 100644
index 0000000..b3defaf
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/markad.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/mlist.png b/skins/default/graphics/menuicons/pluginicons/mlist.png
new file mode 100644
index 0000000..19c367f
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/mlist.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/music.png b/skins/default/graphics/menuicons/pluginicons/music.png
new file mode 100644
index 0000000..abb012e
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/music.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/noepg.png b/skins/default/graphics/menuicons/pluginicons/noepg.png
new file mode 100644
index 0000000..eb9410d
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/noepg.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/nordlichtsepg.png b/skins/default/graphics/menuicons/pluginicons/nordlichtsepg.png
new file mode 100644
index 0000000..3ee3fa2
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/nordlichtsepg.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/osdteletext.png b/skins/default/graphics/menuicons/pluginicons/osdteletext.png
new file mode 100644
index 0000000..664e770
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/osdteletext.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/peer.png b/skins/default/graphics/menuicons/pluginicons/peer.png
new file mode 100644
index 0000000..998d568
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/peer.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/play.png b/skins/default/graphics/menuicons/pluginicons/play.png
new file mode 100644
index 0000000..2848fc6
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/play.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/pvrinput.png b/skins/default/graphics/menuicons/pluginicons/pvrinput.png
new file mode 100644
index 0000000..724f698
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/pvrinput.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/quickepgsearch.png b/skins/default/graphics/menuicons/pluginicons/quickepgsearch.png
new file mode 100644
index 0000000..76a31f4
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/quickepgsearch.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/radio.png b/skins/default/graphics/menuicons/pluginicons/radio.png
new file mode 100644
index 0000000..193b7d4
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/radio.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/remote.png b/skins/default/graphics/menuicons/pluginicons/remote.png
new file mode 100644
index 0000000..7f46b1b
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/remote.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/remotetimers.png b/skins/default/graphics/menuicons/pluginicons/remotetimers.png
new file mode 100644
index 0000000..fae3b79
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/remotetimers.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/rssreader.png b/skins/default/graphics/menuicons/pluginicons/rssreader.png
new file mode 100644
index 0000000..db538f0
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/rssreader.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/sc.png b/skins/default/graphics/menuicons/pluginicons/sc.png
new file mode 100644
index 0000000..2472d6c
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/sc.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/scraper2vdr.png b/skins/default/graphics/menuicons/pluginicons/scraper2vdr.png
new file mode 100644
index 0000000..a106cb5
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/scraper2vdr.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/screenshot.png b/skins/default/graphics/menuicons/pluginicons/screenshot.png
new file mode 100644
index 0000000..be9b4d5
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/screenshot.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/seduatmo.png b/skins/default/graphics/menuicons/pluginicons/seduatmo.png
new file mode 100644
index 0000000..4b5292f
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/seduatmo.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/skyselectfeeds.png b/skins/default/graphics/menuicons/pluginicons/skyselectfeeds.png
new file mode 100644
index 0000000..d81a024
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/skyselectfeeds.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/sleeptimer.png b/skins/default/graphics/menuicons/pluginicons/sleeptimer.png
new file mode 100644
index 0000000..cd4956f
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/sleeptimer.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/softhddevice.png b/skins/default/graphics/menuicons/pluginicons/softhddevice.png
new file mode 100644
index 0000000..df13f2c
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/softhddevice.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/streamdev-server.png b/skins/default/graphics/menuicons/pluginicons/streamdev-server.png
new file mode 100644
index 0000000..e89ed8b
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/streamdev-server.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/systeminfo.png b/skins/default/graphics/menuicons/pluginicons/systeminfo.png
new file mode 100644
index 0000000..b14763f
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/systeminfo.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/targavfd.png b/skins/default/graphics/menuicons/pluginicons/targavfd.png
new file mode 100644
index 0000000..e91b111
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/targavfd.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/trayopenng.png b/skins/default/graphics/menuicons/pluginicons/trayopenng.png
new file mode 100644
index 0000000..6ebd17d
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/trayopenng.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/tvguide.png b/skins/default/graphics/menuicons/pluginicons/tvguide.png
new file mode 100644
index 0000000..968a37c
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/tvguide.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/tvm2vdr.png b/skins/default/graphics/menuicons/pluginicons/tvm2vdr.png
new file mode 100644
index 0000000..47f9a91
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/tvm2vdr.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/tvscraper.png b/skins/default/graphics/menuicons/pluginicons/tvscraper.png
new file mode 100644
index 0000000..a106cb5
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/tvscraper.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/undelete.png b/skins/default/graphics/menuicons/pluginicons/undelete.png
new file mode 100644
index 0000000..a53d50a
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/undelete.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/weatherng.png b/skins/default/graphics/menuicons/pluginicons/weatherng.png
new file mode 100644
index 0000000..a88f11d
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/weatherng.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/xmltv2vdr.png b/skins/default/graphics/menuicons/pluginicons/xmltv2vdr.png
new file mode 100644
index 0000000..ea73c74
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/xmltv2vdr.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/pluginicons/yaepghg.png b/skins/default/graphics/menuicons/pluginicons/yaepghg.png
new file mode 100644
index 0000000..53ce443
--- /dev/null
+++ b/skins/default/graphics/menuicons/pluginicons/yaepghg.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/CAM.png b/skins/default/graphics/menuicons/standardicons/CAM.png
new file mode 100644
index 0000000..a394877
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/CAM.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/Channels.png b/skins/default/graphics/menuicons/standardicons/Channels.png
new file mode 100644
index 0000000..ba2ba78
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/Channels.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/Commands.png b/skins/default/graphics/menuicons/standardicons/Commands.png
new file mode 100644
index 0000000..c6a83ef
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/Commands.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/DVB.png b/skins/default/graphics/menuicons/standardicons/DVB.png
new file mode 100644
index 0000000..3789145
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/DVB.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/EPG.png b/skins/default/graphics/menuicons/standardicons/EPG.png
new file mode 100644
index 0000000..e868b90
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/EPG.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/LNB.png b/skins/default/graphics/menuicons/standardicons/LNB.png
new file mode 100644
index 0000000..896dd99
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/LNB.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/Miscellaneous.png b/skins/default/graphics/menuicons/standardicons/Miscellaneous.png
new file mode 100644
index 0000000..2a41c4d
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/Miscellaneous.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/OSD.png b/skins/default/graphics/menuicons/standardicons/OSD.png
new file mode 100644
index 0000000..8f571c6
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/OSD.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/Plugins.png b/skins/default/graphics/menuicons/standardicons/Plugins.png
new file mode 100644
index 0000000..3fcba70
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/Plugins.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/Recording.png b/skins/default/graphics/menuicons/standardicons/Recording.png
new file mode 100644
index 0000000..741b1af
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/Recording.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/Recordings.png b/skins/default/graphics/menuicons/standardicons/Recordings.png
new file mode 100644
index 0000000..79aeeb7
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/Recordings.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/Replay.png b/skins/default/graphics/menuicons/standardicons/Replay.png
new file mode 100644
index 0000000..621596c
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/Replay.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/Restart.png b/skins/default/graphics/menuicons/standardicons/Restart.png
new file mode 100644
index 0000000..aa23cd4
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/Restart.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/Schedule.png b/skins/default/graphics/menuicons/standardicons/Schedule.png
new file mode 100644
index 0000000..3a98cac
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/Schedule.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/Setup.png b/skins/default/graphics/menuicons/standardicons/Setup.png
new file mode 100644
index 0000000..d121148
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/Setup.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/StopRecording.png b/skins/default/graphics/menuicons/standardicons/StopRecording.png
new file mode 100644
index 0000000..ed83fbb
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/StopRecording.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/StopReplay.png b/skins/default/graphics/menuicons/standardicons/StopReplay.png
new file mode 100644
index 0000000..9192760
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/StopReplay.png
Binary files differ
diff --git a/skins/default/graphics/menuicons/standardicons/Timers.png b/skins/default/graphics/menuicons/standardicons/Timers.png
new file mode 100644
index 0000000..b866c36
--- /dev/null
+++ b/skins/default/graphics/menuicons/standardicons/Timers.png
Binary files differ
diff --git a/skins/default/xmlfiles/displayaudiotracks.xml b/skins/default/xmlfiles/displayaudiotracks.xml
new file mode 100644
index 0000000..9698262
--- /dev/null
+++ b/skins/default/xmlfiles/displayaudiotracks.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displayaudiotracks SYSTEM "../../dtd/displayaudiotracks.dtd">
+
+<displayaudiotracks x="25%" y="0" width="50%" height="100%" fadetime="{fadeTime}">
+ <!-- Available Variables background:
+ {numtracks} number of displayed tracks
+ -->
+ <background>
+ <area x="0" y="{areaheight} - {numtracks} * {areaheight} / 10 - {areaheight} / 10" width="100%" height="{areaheight} / 10 + {areaheight} / 10 * {numtracks}" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ </background>
+
+ <!-- Available Variables header:
+ {numtracks} number of displayed tracks
+ {title} title of menu
+ -->
+ <header>
+ <area x="0" y="{areaheight} - {numtracks} * {areaheight} / 10 - {areaheight} / 10" width="100%" height="{areaheight} / 10" layer="2">
+ <drawtext x="10" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{title}" />
+ <drawimage condition="{isstereo}" imagetype="icon" path="ico_stereo" x="{areawidth} - {areaheight}*0.9" valign="center" width="{areaheight}*0.9" height="{areaheight}*0.9"/>
+ <drawimage condition="{isac3}" imagetype="icon" path="ico_ac3" x="{areawidth} - {areaheight}*0.9" valign="center" width="{areaheight}*0.9" height="{areaheight}*0.9"/>
+ </area>
+ </header>
+
+ <!-- Available Variables header:
+ {numelements} number of displayed tracks
+ -->
+ <menuitems x="0" y="{areaheight} - {numelements} * {areaheight} / 10" orientation="vertical" width="100%" height="{numelements} * {areaheight} / 10" align="top" numlistelements="{numelements}">
+ <!-- Available Variables auidotrack listelement:
+ {current} true if item is currently selected
+ {title} title of auio track
+ -->
+ <listelement>
+ <!-- Background -->
+ <area x="1%" width="98%" layer="2">
+ <fill condition="not{current}" color="{clrTransparent}" />
+ <fill condition="{current}" color="{clrTransBlueLight}" />
+ </area>
+ <area x="1%" width="98%" layer="3">
+ <drawtext x="10" valign="center" font="{light}" fontsize="60%" color="{clrWhite}" text="{title}" />
+ </area>
+ </listelement>
+ </menuitems>
+
+</displayaudiotracks>
diff --git a/skins/default/xmlfiles/displaychannel.xml b/skins/default/xmlfiles/displaychannel.xml
new file mode 100644
index 0000000..6162562
--- /dev/null
+++ b/skins/default/xmlfiles/displaychannel.xml
@@ -0,0 +1,213 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displaychannel SYSTEM "../../dtd/displaychannel.dtd">
+
+<displaychannel x="0" y="0" width="100%" height="100%" fadetime="{fadeTime}">
+ <background>
+ <!-- background infobar -->
+ <area x="0" y="80%" width="100%" height="20%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <!-- background datetime -->
+ <area x="70%" y="0" width="30%" height="13%" layer="1">
+ <fill color="{clrTransBlack}" />
+ <drawrectangle x="0" y="0" width="45%" height="100%" color="{clrTransBlueLight}" />
+ </area>
+ <!-- background channellogo -->
+ <area x="0" y="80%" width="20%" height="20%" layer="2">
+ <fill color="{clrTransBlueLight}" />
+ </area>
+ </background>
+
+ <!-- Available Variables channelinfo:
+ {channelnumber} Number of Channel, with "-" in case of channel switching
+ {channelname} Name of current Channel
+ {channellogoexists} true if a channel logo exists
+ {channelid} ChannelID as path to display channel logo
+ {switching} true if a number is pressed on the remote to switch to a dedicated channel
+ -->
+ <channelinfo>
+ <area x="22%" y="80%" width="76%" height="7%" layer="2">
+ <fill condition="not{switching}" color="{clrTransparent}" />
+ <drawtext condition="{switching}" x="0" y="-10" font="{light}" fontsize="99%" color="{clrWhite}" text="{channelnumber}: {channelname}" />
+ </area>
+ <area x="0" y="80%" width="20%" height="20%" layer="3">
+ <drawimage cache="true" condition="{channellogoexists}" imagetype="channellogo" path="{channelid}" height="98%" align="center" valign="center" />
+ <drawtext condition="not{channellogoexists}" x="5" valign="center" font="{light}" fontsize="40%" color="{clrWhite}" text="{channelnumber}: {channelname}" />
+ </area>
+ </channelinfo>
+ <!-- Available Variables epginfo:
+ {currenttitle} Title of the current Schedule
+ {currentsubtitle} Subtitle of the current Schedule
+ {currentstart} Start of current Schedule in hh:mm
+ {currentstop} End of current Schedule in hh:mm
+ {currentduration} Duration of current Schedule in min
+ {currentelapsed} Elapsed time of current Schedule in min
+ {currentremaining} Remaining time of current Schedule in min
+ {currentrecording} true if current Schedule is recorded
+ {nexttitle} Title of next Schedule
+ {nextsubtitle} Subtitle of next Schedule
+ {nextstart} Start of next Schedule in hh:mm
+ {nextstop} Stop of next Schedule in hh:mm
+ {nextduration} Duration of next Schedule in min
+ {nextrecording} true if next Schedule will be recorded
+ -->
+ <epginfo>
+ <area x="22%" y="80%" width="76%" height="7%" layer="2">
+ <drawtext name="title" x="0" valign="center" font="{light}" fontsize="99%" color="{clrWhite}" text="{currenttitle}" width="{areawidth} - {width(startstop)}"/>
+ <drawtext name="startstop" align="right" y="0" font="{light}" fontsize="60%" color="{clrWhite}" text="{currentstart} - {currentstop}" />
+ <drawtext align="right" y="45%" font="{light}" fontsize="60%" color="{clrWhite}" text="+ {currentremaining} min" />
+ </area>
+ <area x="22%" y="87%" width="76%" height="7%" layer="2">
+ <drawtext x="0" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{nexttitle}" width="{areawidth} - {width(startstop)}"/>
+ <drawtext name="startstop" align="right" y="0" font="{light}" fontsize="60%" color="{clrWhite}" text="{nextstart} - {nextstop}" />
+ <drawtext align="right" y="45%" font="{light}" fontsize="60%" color="{clrWhite}" text="{nextduration} min" />
+ </area>
+ </epginfo>
+
+ <!-- Available Variables progressbar:
+ {start} Start of current Schedule in hh:mm
+ {stop} End of current Schedule in hh:mm
+ {duration} Total Duration of current Schedule in seconds
+ {elapsed} Elapsed time of current Schedule in seconds
+ {remaining} Remaining time of current Schedule in seconds
+ -->
+ <progressbar>
+ <area x="22%" y="87%" width="76%" height="3" layer="2">
+ <drawrectangle x="0" y="1" width="100%" height="1" color="{clrWhite}" />
+ <drawrectangle x="0" y="0" width="{elapsed}/{duration}*{areawidth}" height="3" color="{clrTransBlueLight}" />
+ </area>
+ </progressbar>
+
+ <!-- Available Variables statusinfo:
+ {isRadio} true if channel is a radio channel
+ {hasVT} true if channel has video text
+ {isStereo} true if a stereo audio trac is available
+ {isDolby} true if a dolby audio track is available
+ {isEncrypted} true if channel is encrypted
+ {isRecording} true if currently a recording is running on this channel
+ -->
+ <statusinfo>
+ <area x="22%" y="94%" width="76%" height="6%" layer="2">
+ <!-- encrypted / decrypted icon -->
+ <drawimage name="enc" condition="{isEncrypted}" imagetype="icon" path="ico_crypt_on" x="{areawidth} - {width(enc)}" valign="center" width="{areaheight}*0.8*1.76" height="{areaheight}*0.8"/>
+ <drawimage condition="not{isEncrypted}" imagetype="icon" path="ico_crypt_off" x="{areawidth} - {width(enc)}" valign="center" width="{areaheight}*0.8*1.76" height="{areaheight}*0.8"/>
+ <!-- dolby icon -->
+ <drawimage name="dolby" condition="{isDolby}" imagetype="icon" path="ico_dolby_on" x="{posx(enc)} - 15 - {width(dolby)}" valign="center" width="{areaheight}*0.8*1.48" height="{areaheight}*0.8"/>
+ <drawimage condition="not{isDolby}" imagetype="icon" path="ico_dolby_off" x="{posx(enc)} - 15 - {width(dolby)}" valign="center" width="{areaheight}*0.8*1.48" height="{areaheight}*0.8"/>
+ <!-- videotext icon -->
+ <drawimage name="txt" condition="{hasVT}" imagetype="icon" path="ico_txt_on" x="{posx(dolby)} - 15 - {width(txt)}" valign="center" width="{areaheight}*0.8*1.3" height="{areaheight}*0.8"/>
+ <drawimage condition="not{hasVT}" imagetype="icon" path="ico_txt_off" x="{posx(dolby)} - 15 - {width(txt)}" valign="center" width="{areaheight}*0.8*1.3" height="{areaheight}*0.8"/>
+ <!-- recording icon -->
+ <drawimage name="rec" condition="{isRecording}" imagetype="icon" path="ico_rec_on" x="{posx(txt)} - 15 - {width(rec)}" valign="center" width="{areaheight}*0.8*1.96" height="{areaheight}*0.8"/>
+ <drawimage condition="not{isRecording}" imagetype="icon" path="ico_rec_off" x="{posx(txt)} - 15 - {width(rec)}" valign="center" width="{areaheight}*0.8*1.96" height="{areaheight}*0.8"/>
+ </area>
+ </statusinfo>
+
+ <!-- Available Variables screenresolution:
+ {screenwidth} width of currently displayed channel in px
+ {screenheight} height of currently displayed channel in px
+ {resolution} resolution: hd1080i, hd720p, sd576i
+ {aspect} screen aspect, each 4:3, 16:9 or 21:9
+ {isHD} true for hd1080i and hd720p
+ {isWideScreen} true if aspect is 16:9 or 21:9
+ -->
+ <screenresolution>
+ <area x="22%" y="94%" width="76%" height="6%" layer="2">
+ <!-- widescreen icon -->
+ <drawimage name="widescreen" condition="{isWideScreen}" imagetype="icon" path="ico_widescreen_on" x="{areawidth} - {areaheight}*0.8*1.76 - 15 - {areaheight}*0.8*1.48 - 15 - {areaheight}*0.8*1.3 - 15 - {areaheight}*0.8*1.96 - 15 - {width(widescreen)}" valign="center" width="{areaheight}*0.8*1.87" height="{areaheight}*0.8"/>
+ <drawimage condition="not{isWideScreen}" imagetype="icon" path="ico_widescreen_off" x="{areawidth} - {areaheight}*0.8*1.76 - 15 - {areaheight}*0.8*1.48 - 15 - {areaheight}*0.8*1.3 - 15 - {areaheight}*0.8*1.96 - 15 - {width(widescreen)}" valign="center" width="{areaheight}*0.8*1.87" height="{areaheight}*0.8"/>
+ <!-- hd/sd icon -->
+ <drawimage name="hd" condition="{isHD}" imagetype="icon" path="ico_hd_on" x="{posx(widescreen)} - 15 - {width(hd)}" valign="center" width="{areaheight}*0.8*2.04" height="{areaheight}*0.8"/>
+ <drawimage condition="not{isHD}" imagetype="icon" path="ico_hd_off" x="{posx(widescreen)} - 15 - {width(hd)}" valign="center" width="{areaheight}*0.8*2.04" height="{areaheight}*0.8"/>
+ <!-- screenresolution text -->
+ <drawtext name="reslabel" x="{posx(hd)} - 30 - {width(reslabel)}" valign="center" font="{light}" fontsize="70%" color="{clrWhite}" text="{screenwidth}x{screenheight}" />
+ </area>
+ </screenresolution>
+
+ <!-- Available Variables dvbdeviceinfo:
+ {prevAvailable} true if previous Channel Group is avaialble
+ {nextAvailable} true if next Channel Group is avaialble
+ {group} Name of current Channel Group
+ {nextgroup} Name of next Channel Group
+ {prevgroup} Name of prev Channel Group
+ {sepexists} true if a channel separator logo exists
+ {seppath} path for separator logo to use in imagetype "seplogo"
+ -->
+ <channelgroup>
+ <area x="0" y="80%" width="20%" height="20%" layer="2">
+ <drawimage condition="{sepexists}" imagetype="seplogo" path="{seppath}" height="98%" align="center" valign="center" />
+ <drawimage condition="not{sepexists}" imagetype="icon" path="ico_channelsep" align="center" valign="center" width="{areaheight}*0.8" height="{areaheight}*0.8"/>
+ </area>
+ <area x="22%" y="85%" width="76%" height="10%" layer="2">
+ <drawtext x="0" width="30%" valign="center" font="{light}" fontsize="60%" color="{clrWhite}" text="{prevgroup}" />
+ <drawtext x="30%" width="40%" valign="center" font="{semibold}" fontsize="80%" color="{clrWhite}" text="{group}" />
+ <drawtext align="right" width="30%" valign="center" font="{light}" fontsize="60%" color="{clrWhite}" text="{nextgroup}" />
+ </area>
+ </channelgroup>
+
+ <!-- Available Variables signalquality:
+ {signalstrength} STR value of currently displayed channel
+ {signalquality} SNR value of currently displayed channel
+ -->
+ <signalquality>
+ <area x="22%" y="94%" width="76%" height="6%" layer="3">
+ <drawtext x="0" valign="center" font="{light}" fontsize="70%" color="{clrWhite}" text="STR: {signalstrength}% SNR: {signalquality}%" />
+ </area>
+ </signalquality>
+
+ <!-- background of signalmeter, will only be drawn if signalquality was deleted -->
+ <signalqualityback>
+ </signalqualityback>
+
+ <!-- Available Variables scrapercontent:
+ {mediapath} Full Path of Poster or Banner to use in image path attribute
+ {mediawidth} width of image in pixel
+ {mediaheight} height of image in pixel
+ {isbanner} true if image is a banner, false if it is a poster
+ -->
+ <scrapercontent>
+ <area condition="{isbanner}" x="0" y="0" width="{areaheight}*0.13*{mediawidth}/{mediaheight}" height="13%" layer="2">
+ <drawimage imagetype="image" path="{mediapath}" align="center" valign="center" width="{areawidth}" height="{areaheight}"/>
+ </area>
+ <area condition="not{isbanner}" x="0" y="0" width="{areaheight}*0.5*{mediawidth}/{mediaheight}" height="50%" layer="2">
+ <drawimage imagetype="image" path="{mediapath}" x="5" y="5" width="{areawidth}-10" height="{areaheight}-10"/>
+ </area>
+ </scrapercontent>
+
+ <!-- Available Variables datetime:
+ {time} time in hh:mm
+ {day} day in digits
+ {dayleadingzero} day in digits with leading 0
+ {dayname} Full name of the day
+ {daynameshort} Short 3 char name of the day
+ {month} month in digits with leading 0
+ {monthname} Full name of the month
+ {monthnameshort} 3 letter abbrivation of month name
+ {year} year in yyyy
+ -->
+ <datetime>
+ <area x="70%" y="0" width="13%" height="13%" layer="2">
+ <drawtext align="right" y="0" font="{light}" fontsize="50%" color="{clrWhite}" text="{dayname}" />
+ <drawtext align="right" y="48%" font="{light}" fontsize="50%" color="{clrWhite}" text="{day}. {monthnameshort}" />
+ </area>
+ <area x="85%" y="0" width="13%" height="13%" layer="2">
+ <drawtext align="center" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{time}" />
+ </area>
+ </datetime>
+ <!-- Available Variables message:
+ {text} message text
+ {status} true if message is a status message
+ {info} true if message is a info message
+ {warning} true if message is a warn message
+ {error} true if message is a error message
+ -->
+ <message>
+ <area x="10%" y="45%" width="80%" height="10%" layer="1">
+ <drawrectangle condition="{status}" x="20" y="0" width="20" height="100%" color="{clrGreen}" />
+ <drawrectangle condition="{info}" x="20" y="0" width="20" height="100%" color="{clrBlue}" />
+ <drawrectangle condition="{warning}" x="20" y="0" width="20" height="100%" color="{clrYellow}" />
+ <drawrectangle condition="{error}" x="20" y="0" width="20" height="100%" color="{clrRed}" />
+ <drawtext align="center" valign="center" width="{areawidth} - 80" font="{light}" fontsize="40%" color="{clrWhite}" text="{text}" />
+ </area>
+ </message>
+</displaychannel>
diff --git a/skins/default/xmlfiles/displaymenu.xml b/skins/default/xmlfiles/displaymenu.xml
new file mode 100644
index 0000000..9125d43
--- /dev/null
+++ b/skins/default/xmlfiles/displaymenu.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displaymenu SYSTEM "../../dtd/displaymenu.dtd" [
+<!ENTITY displaymenudefault SYSTEM "displaymenudefault.xml">
+<!ENTITY displaymenumain SYSTEM "displaymenumain.xml">
+<!ENTITY displaymenusetup SYSTEM "displaymenusetup.xml">
+<!ENTITY displaymenuschedules SYSTEM "displaymenuschedules.xml">
+<!ENTITY displaymenutimers SYSTEM "displaymenutimers.xml">
+<!ENTITY displaymenuchannels SYSTEM "displaymenuchannels.xml">
+<!ENTITY displaymenurecordings SYSTEM "displaymenurecordings.xml">
+<!ENTITY displaymenudetailepg SYSTEM "displaymenudetailepg.xml">
+<!ENTITY displaymenudetailrecording SYSTEM "displaymenudetailrecording.xml">
+<!ENTITY displaymenudetailtext SYSTEM "displaymenudetailtext.xml">
+]>
+
+<displaymenu x="3%" y="5%" width="94%" height="90%" fadetime="0">
+ <!--
+ The following background, header, datetime and colorbuttons definitions are default
+ implementations. If one or more of these elements are not implemented in the subview,
+ the default implementations are used.
+ -->
+ <background>
+ <!-- background left Menu -->
+ <area x="0" y="0" width="63%" height="100%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <!-- background right detail view -->
+ <area x="63%" y="3%" width="37%" height="94%" layer="1">
+ <fill color="{clrTransBlueLight}" />
+ </area>
+ </background>
+ <!-- Available Variables header:
+ {title} title of current menu
+ {vdrversion} running VDR Version
+ {hasicon} true if a menu icon is available
+ {icon} path of menu icon
+ -->
+ <header>
+ <area x="0" y="0" width="41%" height="10%" layer="2">
+ <drawtext condition="not{hasicon}" x="5" width="{areawidth}-10" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{title}" />
+ <drawimage condition="{hasicon}" name="menuicon" imagetype="menuicon" path="{icon}" x="5" valign="center" width="{areaheight}*8/10" height="80%"/>
+ <drawtext condition="{hasicon}" x="{areaheight}" valign="center" width="{areawidth}-{areaheight}-10" font="{light}" fontsize="80%" color="{clrWhite}" text="{title}" />
+ </area>
+ </header>
+ <!-- Available Variables datetime:
+ {time} time in hh:mm
+ {day} day in digits
+ {dayleadingzero} day in digits with leading 0
+ {dayname} Full name of the day
+ {daynameshort} Short 3 char name of the day
+ {month} month in digits with leading 0
+ {monthname} Full name of the month
+ {monthnameshort} 3 letter abbrivation of month name
+ {year} year in yyyy
+ -->
+ <datetime>
+ <area x="41%" y="0" width="12%" height="10%" layer="2">
+ <drawtext align="right" y="5%" font="{light}" fontsize="50%" color="{clrWhite}" text="{dayname}" />
+ <drawtext align="right" y="45%" font="{light}" fontsize="50%" color="{clrWhite}" text="{day}. {monthnameshort}" />
+ </area>
+ <area x="53%" y="0" width="10%" height="10%" layer="2">
+ <drawtext align="center" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{time}" />
+ </area>
+ </datetime>
+ <!-- Available Variables message:
+ {text} message text
+ {status} true if message is an status message
+ {info} true if message is an info message
+ {warning} true if message is an warn message
+ {error} true if message is an error message
+ -->
+ <message>
+ <area x="5%" y="75%" width="90%" height="15%" layer="7">
+ <fill color="{clrTransBlack}" />
+ <drawrectangle condition="{status}" x="10" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawrectangle condition="{info}" x="10" y="0" width="10" height="100%" color="{clrBlue}" />
+ <drawrectangle condition="{warning}" x="10" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawrectangle condition="{error}" x="10" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext align="center" valign="center" font="{light}" fontsize="50%" color="{clrWhite}" text="{text}" />
+ </area>
+ </message>
+ <!-- Available Variables colorbuttons:
+ {red1} true if red button is button 1
+ {red2} true if red button is button 2
+ {red3} true if red button is button 3
+ {red4} true if red button is button 4
+ {green1} true if green button is button 1
+ {green2} true if green button is button 2
+ {green3} true if green button is button 3
+ {green4} true if green button is button 4
+ {yellow1} true if yellow button is button 1
+ {yellow2} true if yellow button is button 2
+ {yellow3} true if yellow button is button 3
+ {yellow4} true if yellow button is button 4
+ {blue1} true if blue button is button 1
+ {blue2} true if blue button is button 2
+ {blue3} true if blue button is button 3
+ {blue4} true if blue button is button 4
+ {red} label of red button
+ {green} label of green button
+ {yellow} label of yellow button
+ {blue} label of blue button
+ -->
+ <colorbuttons>
+ <area x="0" y="92%" width="15%" height="8%" layer="2">
+ <drawtext condition="{red1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red1}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green1}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow1}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue1}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="15%" y="92%" width="15%" height="8%" layer="2">
+ <drawtext condition="{red2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red2}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green2}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow2}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue2}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="30%" y="92%" width="15%" height="8%" layer="2">
+ <drawtext condition="{red3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red3}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green3}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow3}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue3}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="45%" y="92%" width="15%" height="8%" layer="2">
+ <drawtext condition="{red4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red4}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green4}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow4}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue4}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ </colorbuttons>
+ &displaymenudefault;
+ &displaymenumain;
+ &displaymenusetup;
+ &displaymenuschedules;
+ &displaymenutimers;
+ &displaymenuchannels;
+ &displaymenurecordings;
+ &displaymenudetailepg;
+ &displaymenudetailrecording;
+ &displaymenudetailtext;
+</displaymenu>
diff --git a/skins/default/xmlfiles/displaymenuchannels.xml b/skins/default/xmlfiles/displaymenuchannels.xml
new file mode 100644
index 0000000..cba4cf8
--- /dev/null
+++ b/skins/default/xmlfiles/displaymenuchannels.xml
@@ -0,0 +1,117 @@
+<menuchannels x="0" y="0" width="100%" height="100%" fadetime="0">
+ <menuitems x="0" y="10%" orientation="vertical" width="100%" height="82%" align="center" numlistelements="16">
+ <!-- Available Variables channels menu listelement:
+ {number} number of the displayed channel
+ {name} name of the displayed channel
+ {channelid} ChannelID as path to display channel logo
+ {transponder} Transponder of channel
+ {frequency} Frequency of channel
+ {source} Source of channel (S, C, T)
+ {sourcedescription} Descriptin of source from sources.conf
+ {position} orbital position of the satellite in case this is a DVB-S source
+ {isAtsc} true if channel is a ATSC channel
+ {isCable} true if channel is cable channel
+ {isSat} true if channel is a satellite channel
+ {isTerr} true if channel is terrestrical
+ {presenteventtitle} title of present event on this channel
+ {presenteventstart} present event start time in hh::mm
+ {presenteventstop} present event event stop time in hh::mm
+ {current} true if item is currently selected
+ {separator} true if item is a list separator
+ -->
+ <listelement>
+ <!-- Background -->
+ <area x="1%" width="58%" layer="2">
+ <fill condition="not{current}" color="{clrTransparent}" />
+ <fill condition="{current}" color="{clrTransBlueLight}" />
+ <fill condition="{separator}" color="{clrSemiTransBlack}" />
+ </area>
+ <area condition="not{separator}" x="1%" width="6%" layer="3">
+ <drawimage name="logo" imagetype="channellogo" path="{channelid}" x="10" height="100%" valign="center" />
+ </area>
+ <areascroll condition="not{separator}" scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="7%" width="52%" layer="3">
+ <drawtext name="menutext" x="20" valign="center" font="{light}" fontsize="95%" color="{clrWhite}" text="{number} {name} - {sourcedescription}, Transp. {transponder}" />
+ </areascroll>
+ <area condition="{separator}" x="7%" width="52%" layer="3">
+ <drawtext x="20" valign="center" font="{light}" fontsize="95%" color="{clrWhite}" text="{name}" />
+ </area>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables channels menu currentelement:
+ {number} number of the displayed channel
+ {name} name of the displayed channel
+ {channelid} ChannelID as path to display channel logo
+ {transponder} Transponder of channel
+ {frequency} Frequency of channel
+ {source} Source of channel (S, C, T)
+ {sourcedescription} Descriptin of source from sources.conf
+ {position} orbital position of the satellite in case this is a DVB-S source
+ {isAtsc} true if channel is a ATSC channel
+ {isCable} true if channel is cable channel
+ {isSat} true if channel is a satellite channel
+ {isTerr} true if channel is terrestrical
+ {presenteventtitle} title of present event on this channel
+ {presenteventstart} present event start time in hh::mm
+ {presenteventstop} present event stop time in hh::mm
+ {presenteventshorttext} present event short text
+ {presenteventdescription} present event description
+ {presenteventday} present event name of day
+ {presenteventdate} present event date in dd:mm:yy
+ {presenteventelapsed} present event elapsed time
+ {presenteventduration} present event duration
+ {hasposter} true if a scraped poster is available for this elements present evemt
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {nexteventtitle} title of next event on this channel
+ {nexteventstart} next event start time in hh::mm
+ {nexteventstop} next event event stop time in hh::mm
+ {nexteventshorttext} next event short text
+ {nexteventdescription} next event description
+ {nexteventday} next event name of day
+ {nexteventdate} next event date in dd:mm:yy
+ {nexteventdate} next event duration
+ {schedule[]} array with following 10 schedules
+ {schedule[title]} title of event
+ {schedule[shorttext]} shorttext of event
+ {schedule[start]} start time of event in hh:mm
+ {schedule[stop]} stop time of event in hh:mm
+ -->
+ <currentelement delay="500" fadetime="0">
+ <area x="63%" y="0" width="36%" height="85%" layer="2">
+ <drawimage name="logo" imagetype="channellogo" path="{channelid}" x="10" y="0" width="30%" />
+ <drawtext name="channame" align="right" y="{height(logo)}/2 - {height(channame)}/2" width="65%" font="{semibold}" fontsize="10%" color="{clrWhite}" text="{name}" />
+ <!-- now -->
+ <drawtext name="now" x="2%" y="{height(logo)}" width="96%" font="{semibold}" fontsize="8%" color="{clrWhite}" text="Now: {presenteventtitle}" />
+ <!--progressbar for now -->
+ <drawtext name="start" x="{areawidth}/4 - {width(start)}" y="{height(logo)} + {height(now)}" font="{light}" fontsize="7%" color="{clrWhite}" text="{presenteventstart}" />
+ <drawtext name="stop" x="{areawidth}*3/4" y="{height(logo)} + {height(now)}" font="{light}" fontsize="7%" color="{clrWhite}" text="{presenteventstop}" />
+ <drawrectangle x="{areawidth}/4+10" y="{height(logo)} + {height(now)} + {height(start)} / 2" width="{areawidth}/2 - 20" height="1" color="{clrWhite}" />
+ <drawrectangle x="{areawidth}/4+10" y="{height(logo)} + {height(now)} + {height(start)} / 2 - 2" width="{areawidth}/2 * {presenteventelapsed} / {presenteventduration} - 20 * {presenteventelapsed} / {presenteventduration}" height="5" color="{clrWhite}" />
+ <!-- shorttext and description -->
+ <drawtextbox name="nowshort" x="2%" y="{posy(start)} + {height(start)} + 10" width="96%" font="{light}" fontsize="6%" color="{clrWhite}" text="{presenteventshorttext}" />
+ <drawtextbox name="nowdesc" x="2%" y="{posy(nowshort)} + {height(nowshort)}" width="96%" height="36%" font="{light}" fontsize="6%" color="{clrWhite}" text="{presenteventdescription}" />
+ <!-- next -->
+ <drawtext name="next" x="2%" y="{posy(nowdesc)} + {height(nowdesc)}" width="96%" font="{semibold}" fontsize="7%" color="{clrWhite}" text="Next: {nexteventtitle}" />
+ <drawtext name="nexttime" x="2%" y="{posy(next)} + {height(next)}" width="96%" font="{light}" fontsize="6%" color="{clrWhite}" text="{nexteventstart} - {nexteventstop} ({presenteventduration} min)" />
+ </area>
+ <areascroll mode="forthandback" orientation="vertical" delay="1000" scrollspeed="medium" x="63%" y="85%" width="36%" height="15%" layer="2">
+ <drawtext x="10" y="0" font="{semibold}" fontsize="30%" color="{clrWhite}" text="Following Schedules:" />
+ <loop name="schedule" x="0" y="{areaheight}/4 + 5" orientation="vertical">
+ <drawtext x="10" font="{light}" width="{areawidth}-20" fontsize="30%" color="{clrWhite}" text="{schedule[start]} {schedule[title]}" />
+ </loop>
+ </areascroll>
+ </currentelement>
+ </menuitems>
+ <!-- Available Variables colorbuttons:
+ {height} height in one-tenth of a percent of total height
+ {offset} offset from top in one-tenth of a percent of total height
+ -->
+ <scrollbar>
+ <area x="60%" y="10%" width="2%" height="82%" layer="3">
+ <fill color="{clrWhite}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrWhite}" />
+ </area>
+ </scrollbar>
+</menuchannels> \ No newline at end of file
diff --git a/skins/default/xmlfiles/displaymenudefault.xml b/skins/default/xmlfiles/displaymenudefault.xml
new file mode 100644
index 0000000..c7885d0
--- /dev/null
+++ b/skins/default/xmlfiles/displaymenudefault.xml
@@ -0,0 +1,184 @@
+ <menudefault x="0" y="0" width="100%" height="100%" fadetime="0">
+ <background>
+ <!-- background Menu -->
+ <area x="0" y="0" width="100%" height="100%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ </background>
+ <!-- Available Variables header:
+ {title} title of current menu
+ {vdrversion} running VDR Version
+ {hasicon} true if a menu icon is available
+ {icon} path of menu icon
+ -->
+ <header>
+ <area x="0" y="0" width="75%" height="10%" layer="2">
+ <drawtext condition="not{hasicon}" x="5" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{title}" />
+ <drawimage condition="{hasicon}" name="icon" imagetype="menuicon" path="{icon}" x="5" valign="center" width="{areaheight}*8/10" height="80%"/>
+ <drawtext condition="{hasicon}" x="{areaheight}" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{title}" />
+ </area>
+ </header>
+ <!-- Available Variables datetime:
+ {time} time in hh:mm
+ {day} day in digits
+ {dayleadingzero} day in digits with leading 0
+ {dayname} Full name of the day
+ {daynameshort} Short 3 char name of the day
+ {month} month in digits with leading 0
+ {monthname} Full name of the month
+ {year} year in yyyy
+ -->
+ <datetime>
+ <area x="80%" y="0" width="10%" height="10%" layer="2">
+ <drawtext align="right" y="0%" font="{light}" fontsize="50%" color="{clrWhite}" text="{dayname}" />
+ <drawtext align="right" y="45%" font="{light}" fontsize="50%" color="{clrWhite}" text="{day}. {monthname}" />
+ </area>
+ <area x="90%" y="0" width="10%" height="10%" layer="2">
+ <drawtext align="center" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{time}" />
+ </area>
+ </datetime>
+
+ <!-- Available Variables colorbuttons:
+ {red1} true if red button is button 1
+ {red2} true if red button is button 2
+ {red3} true if red button is button 3
+ {red4} true if red button is button 4
+ {green1} true if green button is button 1
+ {green2} true if green button is button 2
+ {green3} true if green button is button 3
+ {green4} true if green button is button 4
+ {yellow1} true if yellow button is button 1
+ {yellow2} true if yellow button is button 2
+ {yellow3} true if yellow button is button 3
+ {yellow4} true if yellow button is button 4
+ {blue1} true if blue button is button 1
+ {blue2} true if blue button is button 2
+ {blue3} true if blue button is button 3
+ {blue4} true if blue button is button 4
+ {red} label of red button
+ {green} label of green button
+ {yellow} label of yellow button
+ {blue} label of blue button
+ -->
+ <colorbuttons>
+ <area x="0" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red1}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green1}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow1}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue1}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="25%" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red2}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green2}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow2}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue2}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="50%" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red3}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green3}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow3}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue3}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="75%" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red4}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green4}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow4}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue4}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ </colorbuttons>
+
+ <scrollbar>
+ <area x="96%" y="10%" width="2%" height="82%" layer="3">
+ <fill color="{clrWhite}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrWhite}" />
+ </area>
+ </scrollbar>
+ <!-- IMPORTANT: menuitemwidth and determinatefont have to be defined here. menuitemwidth defines the total width of the
+ default menu items, determinatefont the function which sets the actual font to use. With that it is possible to determinate
+ the correct column widths -->
+ <menuitems x="0" y="10%" orientation="vertical" width="100%" height="82%" align="center" menuitemwidth="94%" determinatefont="column1" numlistelements="16">
+ <!-- Available Variables default menu listelement:
+ {column1} text of column1
+ {column2} text of column2
+ {column3} text of column3
+ {column4} text of column4
+ {column5} text of column5
+ {column6} text of column6
+ {column2set} true if column2 is used
+ {column3set} true if column3 is used
+ {column4set} true if column4 is used
+ {column5set} true if column5 is used
+ {column6set} true if column6 is used
+ {column2x} proposed x value of column2
+ {column3x} proposed x value of column3
+ {column4x} proposed x value of column4
+ {column5x} proposed x value of column5
+ {column6x} proposed x value of column6
+ {column1width} proposed width of column1
+ {column2width} proposed width of column2
+ {column3width} proposed width of column3
+ {column4width} proposed width of column4
+ {column5width} proposed width of column5
+ {column6width} proposed width of column6
+ {columnscroll} number of column which should have scrollable text
+ {current} true if column is currently selected
+ {separator} true if column is a list separator
+ -->
+ <listelement>
+ <area x="0" width="95%" layer="2">
+ <fill condition="not{current}" color="{clrTransparent}" />
+ <fill condition="{current}" color="{clrTransBlueLight}" />
+ </area>
+
+ <areascroll scrollelement="column1" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="1%" width="{column1width}" layer="3">
+ <drawtext name="column1" x="{column1x}" width="{column1width}" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{column1}" />
+ </areascroll>
+ <area x="1%" width="100%" layer="3">
+ <drawtext condition="{column2set}" x="{column2x}" valign="center" font="{light}" fontsize="90%" width="{column2width}" color="{clrWhite}" text="{column2}" />
+ <drawtext condition="{column3set}" x="{column3x}" valign="center" font="{light}" fontsize="90%" width="{column3width}" color="{clrWhite}" text="{column3}" />
+ <drawtext condition="{column4set}" x="{column4x}" valign="center" font="{light}" fontsize="90%" width="{column4width}" color="{clrWhite}" text="{column4}" />
+ <drawtext condition="{column5set}" x="{column5x}" valign="center" font="{light}" fontsize="90%" width="{column5width}" color="{clrWhite}" text="{column5}" />
+ <drawtext condition="{column6set}" x="{column6x}" valign="center" font="{light}" fontsize="90%" width="{column6width}" color="{clrWhite}" text="{column6}" />
+ </area>
+ <!--
+ <areascroll condition="not{separator}++eq({columnscroll},1)" scrollelement="column1" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="1%" width="{column1width}" layer="3">
+ <drawtext name="column1" x="{column1x}" width="{column1width}" valign="center" font="{vdrOsd}" fontsize="90%" color="{clrWhite}" text="{column1}" />
+ </areascroll>
+ <area condition="not{separator}++eq({columnscroll},1)" x="1%" width="100%" layer="3">
+ <drawtext condition="{column2set}" x="{column2x}" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{column2}" />
+ <drawtext condition="{column3set}" x="{column3x}" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{column3}" />
+ <drawtext condition="{column4set}" x="{column4x}" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{column4}" />
+ <drawtext condition="{column5set}" x="{column5x}" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{column5}" />
+ <drawtext condition="{column6set}" x="{column6x}" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{column6}" />
+ </area>
+ <areascroll condition="not{separator}++gt({columnscroll},1)" scrollelement="column2" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="{column2x}" width="{column2width}" layer="3">
+ <drawtext name="column2" x="0" width="{column2width}" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{column2}" />
+ </areascroll>
+ <area condition="not{separator}++gt({columnscroll},1)" x="1%" width="100%" layer="3">
+ <drawtext condition="{column1set}" x="{column1x}" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{column1}" />
+ <drawtext condition="{column3set}" x="{column3x}" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{column3}" />
+ <drawtext condition="{column4set}" x="{column4x}" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{column4}" />
+ <drawtext condition="{column5set}" x="{column5x}" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{column5}" />
+ <drawtext condition="{column6set}" x="{column6x}" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{column6}" />
+ </area>
+ -->
+ </listelement>
+ </menuitems>
+</menudefault>
diff --git a/skins/default/xmlfiles/displaymenudetailepg.xml b/skins/default/xmlfiles/displaymenudetailepg.xml
new file mode 100644
index 0000000..7c8c399
--- /dev/null
+++ b/skins/default/xmlfiles/displaymenudetailepg.xml
@@ -0,0 +1,335 @@
+<menudetailedepg x="0" y="0" width="100%" height="100%" fadetime="0">
+ <background>
+ <area x="0" y="0" width="100%" height="100%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <area x="0" y="0" width="100%" height="20%" layer="2">
+ <fill color="{clrTransBlueLight}" />
+ </area>
+ <area x="0" y="85%" width="100%" height="2" layer="3">
+ <fill color="{clrTransBlueLight}" />
+ </area>
+ </background>
+ <!-- dummyheader -->
+ <header>
+ <area x="0" y="0" width="1" height="1" layer="1">
+ <fill color="{clrTransparent}" />
+ </area>
+ </header>
+ <datetime>
+ <area x="0" y="0" width="1" height="1" layer="1">
+ <fill color="{clrTransparent}" />
+ </area>
+ </datetime>
+ <!-- Available Variables colorbuttons:
+ {red1} true if red button is button 1
+ {red2} true if red button is button 2
+ {red3} true if red button is button 3
+ {red4} true if red button is button 4
+ {green1} true if green button is button 1
+ {green2} true if green button is button 2
+ {green3} true if green button is button 3
+ {green4} true if green button is button 4
+ {yellow1} true if yellow button is button 1
+ {yellow2} true if yellow button is button 2
+ {yellow3} true if yellow button is button 3
+ {yellow4} true if yellow button is button 4
+ {blue1} true if blue button is button 1
+ {blue2} true if blue button is button 2
+ {blue3} true if blue button is button 3
+ {blue4} true if blue button is button 4
+ {red} label of red button
+ {green} label of green button
+ {yellow} label of yellow button
+ {blue} label of blue button
+ -->
+ <colorbuttons>
+ <area x="0" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red1}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green1}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow1}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue1}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="25%" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red2}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green2}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow2}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue2}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="50%" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red3}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green3}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow3}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue3}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="75%" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red4}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green4}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow4}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue4}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ </colorbuttons>
+ <!-- Available Variables in detailheader elements:
+ {title} title of event
+ {shorttext} shorttext of event
+ {start} event start time in hh::mm
+ {stop} event stop time
+ {day} day of current event
+ {date} date of current event in dd.mm.yy
+ {running} true if event is currently running
+ {elapsed} elapsed time of event, if not running 0
+ {duration} duration of event
+ {channelid} ChannelID as path to display channel logo
+ {ismovie} true if event is scraped as a movie
+ {isseries} true if event is scraped as a series
+ {posteravailable} true if a poster is available
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {banneravailable} true if a banner is available
+ {bannerwidth} width of banner
+ {bannerheight} height of banner
+ {bannerpath} path of banner
+ {epgpicavailable} true if a epg picture is available
+ {epgpicpath} path of epg picture
+ -->
+ <detailheader>
+ <area x="1%" y="0" width="98%" height="20%" layer="3">
+ <drawimage name="logo" imagetype="channellogo" path="{channelid}" x="0" height="80%" valign="center" />
+ <drawimage condition="{isseries}++{banneravailable}++not{epgpicavailable}" imagetype="image" path="{bannerpath}" x="{areawidth} - {areawidth}/3 - 10" valign="center" width="{areawidth}/3" height="{areawidth}/3 * {bannerheight} / {bannerwidth}"/>
+ <drawimage condition="{ismovie}++{posteravailable}++not{epgpicavailable}" imagetype="image" path="{posterpath}" x="{areawidth} - {areaheight}*8/10" valign="center" width="{areaheight}*8 / 10 * {posterheight} / {posterwidth}" height="{areaheight}*8 / 10"/>
+ <drawimage condition="{epgpicavailable}" imagetype="image" path="{epgpicpath}" x="{areawidth} - {areaheight}*8/10 * 174 / 130" valign="center" width="{areaheight}*8/10 * 174 / 130" height="{areaheight}*8 / 10"/>
+
+ <drawtext name="title" x="{width(logo)} + 20" valign="center" font="{semibold}" fontsize="35%" color="{clrWhite}" text="{title}" />
+ <drawtext name="datetime" x="{width(logo)} + 20" y="{posy(title)} - {height(datetime)}" font="{light}" fontsize="25%" color="{clrWhite}" text="{day} {date} {start} - {stop} ({duration} mins)" />
+ <drawtext name="shorttext" x="{width(logo)} + 20" y="{posy(title)} + {height(title)}" font="{light}" fontsize="25%" color="{clrWhite}" text="{shorttext}" />
+ </area>
+ </detailheader>
+ <!-- Available Variables scrollbar:
+ {height} height in one-tenth of a percent of total height
+ {offset} offset from top in one-tenth of a percent of total height
+ -->
+ <scrollbar>
+ <area x="98%" y="20%" width="2%" height="65%" layer="3">
+ <fill color="{clrWhite}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrWhite}" />
+ </area>
+ </scrollbar>
+ <!-- Available Variables in tab elements:
+ {title} title of event
+ {shorttext} shorttext of event
+ {description} description of event
+ {start} event start time in hh::mm
+ {stop} event stop time
+ {day} day of current event
+ {date} date of current event in dd.mm.yy
+ {running} true if event is currently running
+ {elapsed} elapsed time of event, if not running 0
+ {duration} duration of event
+ {channelid} ChannelID as path to display channel logo
+ {hasreruns} true if reruns of this event are found
+ {reruns[]} array with reruns
+ {reruns[title]} title of rerun
+ {reruns[shorttext]} shorttext of rerun
+ {reruns[date]} date of rerun in dd:mm
+ {reruns[day]} short dayname of rerun
+ {reruns[start]} start time of rerun in hh:mm
+ {reruns[stop]} stop time of rerun in hh:mm
+ {reruns[channelname]} name of channel on which rerun occurs
+ {reruns[channelnumber]} number of channel on which rerun occurs
+ {reruns[channelid]} id of channel on which rerun occurs to display channel logo
+ {reruns[channellogoexists]} true if channel logo exists
+ {epgpic1avaialble} true if first epg picture is available
+ {epgpic2avaialble} true if first epg picture is available
+ {epgpic3avaialble} true if first epg picture is available
+ {epgpic1path} path of first epg picture
+ {epgpic2path} path of second epg picture
+ {epgpic3path} path of third epg picture
+
+ {ismovie} true if event is scraped as a movie
+ Available variables for movies:
+ {movietitle} movie title from themoviedb
+ {movieoriginalTitle} movie original title from themoviedb
+ {movietagline} movie tagline from themoviedb
+ {movieoverview} movie overview from themoviedb
+ {movieadult} true if movie is rated as adult
+ {moviebudget} movie budget from themoviedb in $
+ {movierevenue} movie revenue from themoviedb in $
+ {moviegenres} movie genres from themoviedb
+ {moviehomepage} movie homepage from themoviedb
+ {moviereleasedate} movie release date from themoviedb
+ {movieruntime} movie runtime from themoviedb
+ {moviepopularity} movie popularity from themoviedb
+ {movievoteaverage} movie vote average from themoviedb
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {fanartwidth} width of scraped fanart
+ {fanartheight} height of scraped fanart
+ {fanartpath} absolute path of scraped fanart
+ {movieiscollection} true if movie is part of a collection
+ {moviecollectionName} name of movie collection
+ {collectionposterwidth} width of scraped collection poster
+ {collectionposterheight} height of scraped collection poster
+ {collectionposterpath} absolute path of scraped collection poster
+ {collectionfanartwidth} width of scraped collection fanart
+ {collectionfanartheight} height of scraped collection fanart
+ {collectionfanartpath} absolute path of scraped collection fanart
+ {actors[]} array with movie actors
+ {actors[name]} real name of actor
+ {actors[role]} actor role
+ {actors[thumb]} absolute path of scraped actor thumb
+ {actors[thumbwidth]} width of scraped actor thumb
+ {actors[thumbheight]} height of scraped actor thumb
+
+ {isseries} true if event is scraped as a series
+ Available variables for series:
+ {seriesname} name of series
+ {seriesoverview} series overview
+ {seriesfirstaired} first aired date
+ {seriesnetwork} network which produces series
+ {seriesgenre} series genre
+ {seriesrating} series thetvdb rating
+ {seriesstatus} status of series (running / finished)
+ {episodetitle} title of episode
+ {episodenumber} number of episode
+ {episodeseason} season of episode
+ {episodefirstaired} first aired date of episode
+ {episodegueststars} guest stars of episode
+ {episodeoverview} episode overview
+ {episoderating} user rating for episode
+ {episodeimagewidth} episode image width
+ {episodeimageheight} episode image height
+ {episodeimagepath} episode image path
+ {seasonposterwidth} episode season poster width
+ {seasonposterheight} episode season poster height
+ {seasonposterpath} episode season poster path
+ {seriesposter1width} width of 1st poster
+ {seriesposter1height} height of 1st poster
+ {seriesposter1path} path of 1st poster
+ {seriesposter2width} width of 2nd poster
+ {seriesposter2height} height of 2nd poster
+ {seriesposter2path} path of 2nd poster
+ {seriesposter3width} width of 3rd poster
+ {seriesposter3height} height of 3rd poster
+ {seriesposter3path} path of 3rd poster
+ {seriesfanart1width} width of 1st fanart
+ {seriesfanart1height} height of 1st fanart
+ {seriesfanart1path} path of 1st fanart
+ {seriesfanart2width} width of 2nd fanart
+ {seriesfanart2height} height of 2nd fanart
+ {seriesfanart2path} path of 2nd fanart
+ {seriesfanart3width} width of 3rd fanart
+ {seriesfanart3height} height of 3rd fanart
+ {seriesfanart3path} path of 3rd fanart
+ {seriesbanner1width} width of 1st banner
+ {seriesbanner1height} height of 1st banner
+ {seriesbanner1path} path of 1st banner
+ {seriesbanner2width} width of 2nd banner
+ {seriesbanner2height} height of 2nd banner
+ {seriesbanner2path} path of 2nd banner
+ {seriesbanner3width} width of 3rd banner
+ {seriesbanner3height} height of 3rd banner
+ {seriesbanner3path} path of 3rd fanart
+ {actors[]} array with movie actors
+ {actors[name]} real name of actor
+ {actors[role]} actor role
+ {actors[thumb]} absolute path of scraped actor thumb
+ {actors[thumbwidth]} width of scraped actor thumb
+ {actors[thumbheight]} height of scraped actor thumb
+ -->
+
+ <!-- a tab is one scrolling area, just position and draw as inside a normal area -->
+
+ <!-- TAB EPGINFO -->
+ <tab name="EPG Info" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawtextbox condition="not{isseries}++not{ismovie}" x="0" y="0" width="96%" font="{light}" fontsize="8%" color="{clrWhite}" text="{description}" />
+ <drawimage condition="{isseries}" name="seriesposter" imagetype="image" path="{seriesposter1path}" x="{areawidth}*0.75" y="0" width="{areawidth}*0.25" height="{areawidth} * 0.25 * {seriesposter1height} / {seriesposter1width}"/>
+ <drawimage condition="{ismovie}" name="movieposter" imagetype="image" path="{posterpath}" x="{areawidth}*0.75" y="0" width="{areawidth}*0.25" height="{areawidth} * 0.25 * {posterheight} / {posterwidth}" />
+ <drawtextbox condition="{isseries}" x="0" y="0" width="96%" float="topright" floatwidth="{width(seriesposter)} + 10" floatheight="{height(seriesposter)} + 20" font="{light}" fontsize="8%" color="{clrWhite}" text="{description}" />
+ <drawtextbox condition="{ismovie}" x="0" y="0" width="96%" float="topright" floatwidth="{width(movieposter)} + 10" floatheight="{height(movieposter)} + 20" font="{light}" fontsize="8%" color="{clrWhite}" text="{description}" />
+ </tab>
+ <!-- TAB RERUNS -->
+ <tab condition="{hasreruns}" name="{tr(reruns)}" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawtext align="center" y="0" name="title" font="{light}" fontsize="10%" color="{clrWhite}" text="{tr(rerunsof)} '{title}'" />
+ <loop name="reruns" x="0" y="{height(title)} + 10" width="{areawidth}" orientation="vertical">
+ <drawimage name="logo" condition="{reruns[channellogoexists]}" imagetype="channellogo" path="{reruns[channelid]}" x="0" height="10%" />
+ <drawtext name="channelname" condition="not{reruns[channellogoexists]}" x="-5" font="{light}" fontsize="10%" color="{clrWhite}" text="{reruns[channelname]}" />
+ <drawtext condition="{reruns[channellogoexists]}" x="{width(logo)}+20" y="-5" width="{areawidth} - {width(logo)} - 20" font="{light}" fontsize="8%" color="{clrWhite}" text="{reruns[day]} {reruns[date]} {reruns[start]} - {reruns[stop]}: {reruns[title]} {reruns[shorttext]}" />
+ <drawtext condition="not{reruns[channellogoexists]}" x="{width(channelname)}+20" y="-5" width="{areawidth} - {width(logo)} - 20" font="{light}" fontsize="8%" color="{clrWhite}" text="{reruns[day]} {reruns[date]} {reruns[start]} - {reruns[stop]}: {reruns[title]} {reruns[shorttext]}" />
+ </loop>
+ </tab>
+ <!-- TAB ACTORS -->
+ <tab condition="{isseries}||{ismovie}" name="{tr(actors)}" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawtext align="center" name="title" y="0" font="{semibold}" fontsize="15%" color="{clrWhite}" text="{tr(actors)}" />
+ <loop name="actors" x="0" y="{height(title)} + 10" width="{areawidth}" orientation="horizontal" columnwidth="{areawidth}/5" rowheight="{areawidth}/5*1.8" overflow="linewrap">
+ <drawimage name="thumb" imagetype="image" path="{actors[thumb]}" x="20" y="0" width="{columnwidth}-40" height="{columnwidth} * {actors[thumbheight]} / {actors[thumbwidth]} - 40 * {actors[thumbheight]} / {actors[thumbwidth]}"/>
+ <drawtext align="center" y="{height(thumb)} + 10" width="{columnwidth}" name="actorname" font="{light}" fontsize="7%" color="{clrWhite}" text="{actors[name]}" />
+ <drawtext align="center" y="{height(thumb)} + 10 + {height(actorname)}" width="{columnwidth}" font="{light}" fontsize="7%" color="{clrWhite}" text="{actors[role]}" />
+ </loop>
+ </tab>
+ <!-- TAB TVDBINFO -->
+ <tab condition="{isseries}" name="TvDBInfo" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="banner" imagetype="image" path="{seriesbanner1path}" align="center" y="10" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner1height} / {seriesbanner1width}"/>
+ <drawimage name="episodeimage" imagetype="image" path="{episodeimagepath}" x="{areawidth}*0.7" y="{height(banner)} + 20" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {episodeimageheight} / {episodeimagewidth}"/>
+ <drawimage name="seasonposter" imagetype="image" path="{seasonposterpath}" x="{areawidth}*0.7" y="{height(banner)} + {height(episodeimage)} + 30" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {seasonposterheight} / {seasonposterwidth}"/>
+ <drawtextbox x="0" y="{height(banner)} + 20" width="96%" float="topright" floatwidth="{width(seasonposter)} + 10" floatheight="{height(episodeimage)} + {height(seasonposter)} + 30" font="{light}" fontsize="8%" color="{clrWhite}" text="{tr(episode)}: {episodetitle} ({tr(season)} {episodeseason}, {tr(episode)} {episodenumber}) &#10;&#10;{episodeoverview}|&#10;&#10;{tr(gueststars)}: {episodegueststars}||&#10;&#10;{tr(seriesfirstaired)}: {seriesfirstaired}||&#10;{tr(episodefirstaired)}: {episodefirstaired}||&#10;{tr(network)}: {seriesnetwork}||&#10;{tr(genre)}: {seriesgenre}||&#10;{tr(status)}: {seriesstatus}||&#10;{tr(rating)}: {seriesrating}||&#10;{tr(episoderating)}: {episoderating}&#10;|{seriesoverview}&#10;" />
+ </tab>
+ <!-- TAB SERIESGALERY -->
+ <tab condition="{isseries}" name="{tr(seriesgalery)}" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="banner1" imagetype="image" path="{seriesbanner1path}" align="center" y="10" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner1height} / {seriesbanner1width}"/>
+ <drawimage name="fanart1" imagetype="image" path="{seriesfanart1path}" align="center" y="{posy(banner1)} + {height(banner1)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesfanart1height} / {seriesfanart1width}"/>
+ <drawimage name="banner2" imagetype="image" path="{seriesbanner2path}" align="center" y="{posy(fanart1)} + {height(fanart1)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner2height} / {seriesbanner2width}"/>
+ <drawimage name="fanart2" imagetype="image" path="{seriesfanart2path}" align="center" y="{posy(banner2)} + {height(banner2)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesfanart2height} / {seriesfanart2width}"/>
+ <drawimage name="banner3" imagetype="image" path="{seriesbanner3path}" align="center" y="{posy(fanart2)} + {height(fanart2)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner3height} / {seriesbanner3width}"/>
+ <drawimage name="fanart3" imagetype="image" path="{seriesfanart3path}" align="center" y="{posy(banner3)} + {height(banner3)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesfanart3height} / {seriesfanart3width}"/>
+ <drawimage name="poster1" imagetype="image" path="{seriesposter1path}" align="center" y="{posy(fanart3)} + {height(fanart3)} + 20" width="{areawidth}*0.5" height="{areawidth} * 0.5 * {seriesposter1height} / {seriesposter1width}"/>
+ <drawimage name="poster2" imagetype="image" path="{seriesposter2path}" align="center" y="{posy(poster1)} + {height(poster1)} + 20" width="{areawidth}*0.5" height="{areawidth} * 0.5 * {seriesposter2height} / {seriesposter2width}"/>
+ <drawimage name="poster3" imagetype="image" path="{seriesposter3path}" align="center" y="{posy(poster2)} + {height(poster2)} + 20" width="{areawidth}*0.5" height="{areawidth} * 0.5 * {seriesposter3height} / {seriesposter3width}"/>
+ </tab>
+ <!-- TAB MOVIEDBINFO -->
+ <tab condition="{ismovie}" name="MovieDBInfo" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="poster" imagetype="image" path="{posterpath}" x="70%" y="10" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {posterheight} / {posterwidth}"/>
+ <drawtextbox x="0" y="10" width="96%" float="topright" floatwidth="{width(poster)} + 10" floatheight="{height(poster)} + 20" font="{light}" fontsize="8%" color="{clrWhite}" text="{tr(originaltitle)}: {movieoriginalTitle}&#10;&#10;|{tr(genre)}: {moviegenres}&#10;&#10;||{movietagline}&#10;&#10;|{movieoverview}&#10;&#10;|{tr(budget)}: {moviebudget}&#10;||{tr(revenue)}: {movierevenue}&#10;&#10;||{tr(adult)}: {movieadult}&#10;||{tr(releasedate)}: {moviereleasedate}&#10;||{tr(runtime)}: {movieruntime} min&#10;||&#10;{tr(popularity)}: {moviepopularity}&#10;||&#10;{tr(voteaverage)}: {movievoteaverage}&#10;||&#10;{tr(homepage)}: {moviehomepage}|&#10;" />
+ </tab>
+ <!-- TAB MOVIEGALERY -->
+ <tab condition="{ismovie}" name="{tr(moviegalery)}" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="fanart" imagetype="image" path="{fanartpath}" align="center" y="10" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {fanartheight} / {fanartwidth}"/>
+ <drawimage name="poster" imagetype="image" path="{posterpath}" align="center" y="{height(fanart)} + 30" width="{areawidth}*0.6" height="{areawidth} * 0.6 * {posterheight} / {posterwidth}"/>
+ <drawimage condition="{movieiscollection}" name="collectionfanart" imagetype="image" path="{collectionfanartpath}" align="center" y="{posy(poster)} + {height(poster)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {collectionfanartheight} / {collectionfanartwidth}"/>
+ <drawimage condition="{movieiscollection}" name="collectionposter" imagetype="image" path="{collectionposterpath}" align="center" y="{posy(collectionfanart)} + {height(collectionfanart)} + 20" width="{areawidth}*0.6" height="{areawidth} * 0.6 * {collectionposterheight} / {collectionposterwidth}"/>
+ </tab>
+
+ <!-- Available Variables tablabels:
+ {tabs[]} array with available tab labels
+ {tabs[title]} title of tab
+ {tabs[current]} true if tab is displayed currently
+ -->
+ <tablabels>
+ <area x="0" y="85%" width="98%" height="5%" layer="3">
+ <loop name="tabs" x="0" y="0" orientation="horizontal">
+ <drawrectangle condition="{tabs[current]}" x="0" y="0" width="{width(label)}" height="100%" color="{clrTransBlueLight}" />
+ <drawrectangle condition="not{tabs[current]}" x="0" y="0" width="{width(label)}" height="100%" color="{clrTransBlueLight}" />
+ <drawrectangle condition="not{tabs[current]}" x="2" y="2" width="{width(label)} - 4" height="{areaheight}-4" color="{clrTransparent}" />
+ <drawtext name="label" x="0" valign="center" font="{light}" fontsize="95%" color="{clrWhite}" text=" {tabs[title]} " />
+ </loop>
+ </area>
+ </tablabels>
+</menudetailedepg> \ No newline at end of file
diff --git a/skins/default/xmlfiles/displaymenudetailrecording.xml b/skins/default/xmlfiles/displaymenudetailrecording.xml
new file mode 100644
index 0000000..2342ecc
--- /dev/null
+++ b/skins/default/xmlfiles/displaymenudetailrecording.xml
@@ -0,0 +1,310 @@
+<menudetailedrecording x="0" y="0" width="100%" height="100%" fadetime="0">
+ <background>
+ <area x="0" y="0" width="100%" height="100%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <area x="0" y="0" width="100%" height="20%" layer="2">
+ <fill color="{clrTransBlueLight}" />
+ </area>
+ <area x="0" y="85%" width="100%" height="2" layer="3">
+ <fill color="{clrTransBlueLight}" />
+ </area>
+ </background>
+ <!-- dummyheader -->
+ <header>
+ <area x="0" y="0" width="1" height="1" layer="1">
+ <fill color="{clrTransparent}" />
+ </area>
+ </header>
+ <datetime>
+ <area x="0" y="0" width="1" height="1" layer="1">
+ <fill color="{clrTransparent}" />
+ </area>
+ </datetime>
+ <!-- Available Variables colorbuttons:
+ {red1} true if red button is button 1
+ {red2} true if red button is button 2
+ {red3} true if red button is button 3
+ {red4} true if red button is button 4
+ {green1} true if green button is button 1
+ {green2} true if green button is button 2
+ {green3} true if green button is button 3
+ {green4} true if green button is button 4
+ {yellow1} true if yellow button is button 1
+ {yellow2} true if yellow button is button 2
+ {yellow3} true if yellow button is button 3
+ {yellow4} true if yellow button is button 4
+ {blue1} true if blue button is button 1
+ {blue2} true if blue button is button 2
+ {blue3} true if blue button is button 3
+ {blue4} true if blue button is button 4
+ {red} label of red button
+ {green} label of green button
+ {yellow} label of yellow button
+ {blue} label of blue button
+ -->
+ <colorbuttons>
+ <area x="0" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red1}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green1}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow1}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue1}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="25%" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red2}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green2}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow2}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue2}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="50%" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red3}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green3}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow3}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue3}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="75%" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red4}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green4}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow4}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue4}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ </colorbuttons>
+ <!-- Available Variables in detailheader elements:
+ {name} name of recording
+ {shorttext} shorttext of recording
+ {date} date of recording in dd.mm.yy
+ {time} time of current event in hh:mm
+ {duration} real duration of recording in minutes
+ {durationevent} duration of according event in minutes
+ {ismovie} true if event is scraped as a movie
+ {isseries} true if event is scraped as a series
+ {posteravailable} true if a poster is available
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {banneravailable} true if a banner is available
+ {bannerwidth} width of banner
+ {bannerheight} height of banner
+ {bannerpath} path of banner
+ {recimgavailable} true if a recording image is available in the recording path
+ {recimgpath} path of rec image
+ -->
+ <detailheader>
+ <area x="1%" y="0" width="98%" height="20%" layer="3">
+ <drawimage condition="{isseries}++{banneravailable}++not{recimgavailable}" imagetype="image" path="{bannerpath}" x="{areawidth} - {areawidth}/3 - 10" valign="center" width="{areawidth}/3" height="{areawidth}/3 * {bannerheight} / {bannerwidth}"/>
+ <drawimage condition="{ismovie}++{posteravailable}++not{recimgavailable}" imagetype="image" path="{posterpath}" x="{areawidth} - {areaheight}*8/10" valign="center" width="{areaheight}*8 / 10 * {posterheight} / {posterwidth}" height="{areaheight}*8 / 10"/>
+ <drawimage condition="{recimgavailable}" imagetype="image" path="{recimgpath}" x="{areawidth} - {areaheight}*8/10 * 174 / 130" valign="center" width="{areaheight}*8/10 * 174 / 130" height="{areaheight}*8 / 10"/>
+
+ <drawtext name="title" x="20" valign="center" font="{semibold}" fontsize="35%" color="{clrWhite}" text="{name}" />
+ <drawtext name="datetime" x="20" y="{posy(title)} - {height(datetime)}" font="{light}" fontsize="25%" color="{clrWhite}" text="{date} {time} ({duration} mins)" />
+ <drawtext name="shorttext" x="20" y="{posy(title)} + {height(title)}" font="{light}" fontsize="25%" color="{clrWhite}" text="{shorttext}" />
+ </area>
+ </detailheader>
+ <!-- Available Variables scrollbar:
+ {height} height in one-tenth of a percent of total height
+ {offset} offset from top in one-tenth of a percent of total height
+ -->
+ <scrollbar>
+ <area x="98%" y="20%" width="2%" height="65%" layer="3">
+ <fill color="{clrWhite}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrWhite}" />
+ </area>
+ </scrollbar>
+ <!-- Available Variables in tab elements:
+ {name} title of recording
+ {shorttext} shorttext of recording
+ {description} description of recording
+ {date} date of recording in dd.mm.yy
+ {time} time of recording in hh:mm
+ {duration} real duration of recording in minutes
+ {durationevent} duration of according event in minutes
+
+ {recordingsize} size of recording (automatically in GB / MB)
+ {recordingsizecutted} size of cutted recording (automatically in GB / MB)
+ {recordinglength} length of recording (in hh::mm:ss)
+ {recordinglengthcutted} length of cutted recording (in hh::mm:ss)
+ {recordingbitrate} bitrate of recording (in MBit/s)
+ {recordingformat} format of recording (TS / PS)
+ {searchtimer} name of accordign searchtimer (if available)
+
+ {recimg1avaialble} true if first recording image is available
+ {recimg2avaialble} true if first recording image is available
+ {recimg3avaialble} true if first recording image is available
+ {recimg1path} path of first recording image
+ {recimg2path} path of second recording image
+ {recimg3path} path of third recording image
+
+ {ismovie} true if event is scraped as a movie
+ Available variables for movies:
+ {movietitle} movie title from themoviedb
+ {movieoriginalTitle} movie original title from themoviedb
+ {movietagline} movie tagline from themoviedb
+ {movieoverview} movie overview from themoviedb
+ {movieadult} true if movie is rated as adult
+ {moviebudget} movie budget from themoviedb in $
+ {movierevenue} movie revenue from themoviedb in $
+ {moviegenres} movie genres from themoviedb
+ {moviehomepage} movie homepage from themoviedb
+ {moviereleasedate} movie release date from themoviedb
+ {movieruntime} movie runtime from themoviedb
+ {moviepopularity} movie popularity from themoviedb
+ {movievoteaverage} movie vote average from themoviedb
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {fanartwidth} width of scraped fanart
+ {fanartheight} height of scraped fanart
+ {fanartpath} absolute path of scraped fanart
+ {movieiscollection} true if movie is part of a collection
+ {moviecollectionName} name of movie collection
+ {collectionposterwidth} width of scraped collection poster
+ {collectionposterheight} height of scraped collection poster
+ {collectionposterpath} absolute path of scraped collection poster
+ {collectionfanartwidth} width of scraped collection fanart
+ {collectionfanartheight} height of scraped collection fanart
+ {collectionfanartpath} absolute path of scraped collection fanart
+ {actors[]} array with movie actors
+ {actors[name]} real name of actor
+ {actors[role]} actor role
+ {actors[thumb]} absolute path of scraped actor thumb
+ {actors[thumbwidth]} width of scraped actor thumb
+ {actors[thumbheight]} height of scraped actor thumb
+
+ {isseries} true if event is scraped as a series
+ Available variables for series:
+ {seriesname} name of series
+ {seriesoverview} series overview
+ {seriesfirstaired} first aired date
+ {seriesnetwork} network which produces series
+ {seriesgenre} series genre
+ {seriesrating} series thetvdb rating
+ {seriesstatus} status of series (running / finished)
+ {episodetitle} title of episode
+ {episodenumber} number of episode
+ {episodeseason} season of episode
+ {episodefirstaired} first aired date of episode
+ {episodegueststars} guest stars of episode
+ {episodeoverview} episode overview
+ {episoderating} user rating for episode
+ {episodeimagewidth} episode image width
+ {episodeimageheight} episode image height
+ {episodeimagepath} episode image path
+ {seasonposterwidth} episode season poster width
+ {seasonposterheight} episode season poster height
+ {seasonposterpath} episode season poster path
+ {seriesposter1width} width of 1st poster
+ {seriesposter1height} height of 1st poster
+ {seriesposter1path} path of 1st poster
+ {seriesposter2width} width of 2nd poster
+ {seriesposter2height} height of 2nd poster
+ {seriesposter2path} path of 2nd poster
+ {seriesposter3width} width of 3rd poster
+ {seriesposter3height} height of 3rd poster
+ {seriesposter3path} path of 3rd poster
+ {seriesfanart1width} width of 1st fanart
+ {seriesfanart1height} height of 1st fanart
+ {seriesfanart1path} path of 1st fanart
+ {seriesfanart2width} width of 2nd fanart
+ {seriesfanart2height} height of 2nd fanart
+ {seriesfanart2path} path of 2nd fanart
+ {seriesfanart3width} width of 3rd fanart
+ {seriesfanart3height} height of 3rd fanart
+ {seriesfanart3path} path of 3rd fanart
+ {seriesbanner1width} width of 1st banner
+ {seriesbanner1height} height of 1st banner
+ {seriesbanner1path} path of 1st banner
+ {seriesbanner2width} width of 2nd banner
+ {seriesbanner2height} height of 2nd banner
+ {seriesbanner2path} path of 2nd banner
+ {seriesbanner3width} width of 3rd banner
+ {seriesbanner3height} height of 3rd banner
+ {seriesbanner3path} path of 3rd fanart
+ {actors[]} array with movie actors
+ {actors[name]} real name of actor
+ {actors[role]} actor role
+ {actors[thumb]} absolute path of scraped actor thumb
+ {actors[thumbwidth]} width of scraped actor thumb
+ {actors[thumbheight]} height of scraped actor thumb
+ -->
+
+ <!-- a tab is one scrolling area, just position and draw as inside a normal area -->
+ <tab name="Info" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawtextbox condition="not{isseries}++not{ismovie}" x="0" y="0" width="96%" font="{light}" fontsize="8%" color="{clrWhite}" text="{description}" />
+ <drawimage condition="{isseries}" name="seriesposter" imagetype="image" path="{seriesposter1path}" x="{areawidth}*0.7" y="0" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {seriesposter1height} / {seriesposter1width}"/>
+ <drawimage condition="{ismovie}" name="movieposter" imagetype="image" path="{posterpath}" x="{areawidth}*0.7" y="0" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {posterheight} / {posterwidth}" />
+ <drawtextbox condition="{isseries}" x="0" y="0" width="96%" float="topright" floatwidth="{width(seriesposter)} + 10" floatheight="{height(seriesposter)} + 20" font="{light}" fontsize="8%" color="{clrWhite}" text="{description}" />
+ <drawtextbox condition="{ismovie}" x="0" y="0" width="96%" float="topright" floatwidth="{width(movieposter)} + 10" floatheight="{height(movieposter)} + 20" font="{light}" fontsize="8%" color="{clrWhite}" text="{description}" />
+ </tab>
+ <tab name="{tr(recinfo)}" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawtext align="center" y="0" name="title" font="{light}" fontsize="10%" color="{clrWhite}" text="{tr(recinfo)}" />
+ <drawtextbox x="0" y="{height(title)} + 20" width="96%" font="{light}" fontsize="10%" color="{clrWhite}" text="{tr(recsize)}: {recordingsize}&#10;{tr(recsizecutted)}: {recordingsizecutted}&#10;{tr(reclength)}: {recordinglength}&#10;{tr(reclengthcutted)}: {recordinglengthcutted}&#10;{tr(bitrate)}: {recordingbitrate}&#10;{tr(format)}: {recordingformat}&#10;{tr(searchtimer)}: {searchtimer}&#10;" />
+ </tab>
+ <tab condition="{isseries}||{ismovie}" name="{tr(actors)}" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawtext align="center" name="title" y="0" font="{light}" fontsize="10%" color="{clrWhite}" text="{tr(actors)}" />
+ <loop name="actors" x="0" y="{height(title)} + 10" width="{areawidth}" orientation="horizontal" columnwidth="{areawidth}/5" rowheight="{areawidth}/5*1.8" overflow="linewrap">
+ <drawimage name="thumb" imagetype="image" path="{actors[thumb]}" x="20" y="0" width="{columnwidth}-40" height="{columnwidth} * {actors[thumbheight]} / {actors[thumbwidth]} - 40 * {actors[thumbheight]} / {actors[thumbwidth]}"/>
+ <drawtext align="center" y="{height(thumb)} + 10" width="{columnwidth}" name="actorname" font="{light}" fontsize="7%" color="{clrWhite}" text="{actors[name]}" />
+ <drawtext align="center" y="{height(thumb)} + 10 + {height(actorname)}" width="{columnwidth}" font="{light}" fontsize="7%" color="{clrWhite}" text="{actors[role]}" />
+ </loop>
+ </tab>
+ <tab condition="{isseries}" name="TvDBInfo" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="banner" imagetype="image" path="{seriesbanner1path}" align="center" y="10" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner1height} / {seriesbanner1width}"/>
+ <drawimage name="episodeimage" imagetype="image" path="{episodeimagepath}" x="{areawidth}*0.7" y="{height(banner)} + 20" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {episodeimageheight} / {episodeimagewidth}"/>
+ <drawimage name="seasonposter" imagetype="image" path="{seasonposterpath}" x="{areawidth}*0.7" y="{height(banner)} + {height(episodeimage)} + 30" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {seasonposterheight} / {seasonposterwidth}"/>
+ <drawtextbox x="0" y="{height(banner)} + 20" width="96%" float="topright" floatwidth="{width(seasonposter)} + 10" floatheight="{height(episodeimage)} + {height(seasonposter)} + 30" font="{light}" fontsize="8%" color="{clrWhite}" text="{tr(episode)}: {episodetitle} ({tr(season)} {episodeseason}, {tr(episode)} {episodenumber}) &#10;&#10;{episodeoverview}|&#10;&#10;{tr(gueststars)}: {episodegueststars}||&#10;&#10;{tr(seriesfirstaired)}: {seriesfirstaired}||&#10;{tr(episodefirstaired)}: {episodefirstaired}||&#10;{tr(network)}: {seriesnetwork}||&#10;{tr(genre)}: {seriesgenre}||&#10;{tr(status)}: {seriesstatus}||&#10;{tr(rating)}: {seriesrating}||&#10;{tr(episoderating)}: {episoderating}&#10;|{seriesoverview}&#10;" />
+ </tab>
+ <tab condition="{isseries}" name="{tr(seriesgalery)}" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="banner1" imagetype="image" path="{seriesbanner1path}" align="center" y="10" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner1height} / {seriesbanner1width}"/>
+ <drawimage name="fanart1" imagetype="image" path="{seriesfanart1path}" align="center" y="{posy(banner1)} + {height(banner1)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesfanart1height} / {seriesfanart1width}"/>
+ <drawimage name="banner2" imagetype="image" path="{seriesbanner2path}" align="center" y="{posy(fanart1)} + {height(fanart1)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner2height} / {seriesbanner2width}"/>
+ <drawimage name="fanart2" imagetype="image" path="{seriesfanart2path}" align="center" y="{posy(banner2)} + {height(banner2)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesfanart2height} / {seriesfanart2width}"/>
+ <drawimage name="banner3" imagetype="image" path="{seriesbanner3path}" align="center" y="{posy(fanart2)} + {height(fanart2)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner3height} / {seriesbanner3width}"/>
+ <drawimage name="fanart3" imagetype="image" path="{seriesfanart3path}" align="center" y="{posy(banner3)} + {height(banner3)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesfanart3height} / {seriesfanart3width}"/>
+ <drawimage name="poster1" imagetype="image" path="{seriesposter1path}" align="center" y="{posy(fanart3)} + {height(fanart3)} + 20" width="{areawidth}*0.5" height="{areawidth} * 0.5 * {seriesposter1height} / {seriesposter1width}"/>
+ <drawimage name="poster2" imagetype="image" path="{seriesposter2path}" align="center" y="{posy(poster1)} + {height(poster1)} + 20" width="{areawidth}*0.5" height="{areawidth} * 0.5 * {seriesposter2height} / {seriesposter2width}"/>
+ <drawimage name="poster3" imagetype="image" path="{seriesposter3path}" align="center" y="{posy(poster2)} + {height(poster2)} + 20" width="{areawidth}*0.5" height="{areawidth} * 0.5 * {seriesposter3height} / {seriesposter3width}"/>
+ </tab>
+ <tab condition="{ismovie}" name="MovieDBInfo" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="poster" imagetype="image" path="{posterpath}" x="70%" y="10" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {posterheight} / {posterwidth}"/>
+ <drawtextbox x="0" y="10" width="96%" float="topright" floatwidth="{width(poster)} + 10" floatheight="{height(poster)} + 20" font="{light}" fontsize="8%" color="{clrWhite}" text="{tr(originaltitle)}: {movieoriginalTitle}&#10;&#10;|{tr(genre)}: {moviegenres}&#10;&#10;||{movietagline}&#10;&#10;|{movieoverview}&#10;&#10;|{tr(budget)}: {moviebudget}$&#10;||{tr(revenue)}: {movierevenue}$&#10;&#10;||{tr(adult)}: {movieadult}&#10;||{tr(releasedate)}: {moviereleasedate}&#10;||{tr(runtime)}: {movieruntime} min&#10;||&#10;{tr(popularity)}: {moviepopularity}&#10;||&#10;{tr(voteaverage)}: {movievoteaverage}&#10;||&#10;{tr(homepage)}: {moviehomepage}|&#10;" />
+ </tab>
+ <tab condition="{ismovie}" name="{tr(moviegalery)}" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="fanart" imagetype="image" path="{fanartpath}" align="center" y="10" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {fanartheight} / {fanartwidth}"/>
+ <drawimage name="poster" imagetype="image" path="{posterpath}" align="center" y="{height(fanart)} + 30" width="{areawidth}*0.6" height="{areawidth} * 0.6 * {posterheight} / {posterwidth}"/>
+ <drawimage condition="{movieiscollection}" name="collectionfanart" imagetype="image" path="{collectionfanartpath}" align="center" y="{posy(poster)} + {height(poster)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {collectionfanartheight} / {collectionfanartwidth}"/>
+ <drawimage condition="{movieiscollection}" name="collectionposter" imagetype="image" path="{collectionposterpath}" align="center" y="{posy(collectionfanart)} + {height(collectionfanart)} + 20" width="{areawidth}*0.6" height="{areawidth} * 0.6 * {collectionposterheight} / {collectionposterwidth}"/>
+ </tab>
+
+ <!-- Available Variables tablabels:
+ {tabs[]} array with available tab labels
+ {tabs[title]} title of tab
+ {tabs[current]} true if tab is displayed currently
+ -->
+ <tablabels>
+ <area x="0" y="85%" width="98%" height="5%" layer="3">
+ <loop name="tabs" x="0" y="0" orientation="horizontal">
+ <drawrectangle condition="{tabs[current]}" x="0" y="0" width="{width(label)}" height="100%" color="{clrTransBlueLight}" />
+ <drawrectangle condition="not{tabs[current]}" x="0" y="0" width="{width(label)}" height="100%" color="{clrTransBlueLight}" />
+ <drawrectangle condition="not{tabs[current]}" x="2" y="2" width="{width(label)} - 4" height="{areaheight}-4" color="{clrTransparent}" />
+ <drawtext name="label" x="0" valign="center" font="{light}" fontsize="95%" color="{clrWhite}" text=" {tabs[title]} " />
+ </loop>
+ </area>
+ </tablabels>
+</menudetailedrecording>
diff --git a/skins/default/xmlfiles/displaymenudetailtext.xml b/skins/default/xmlfiles/displaymenudetailtext.xml
new file mode 100644
index 0000000..5fd8997
--- /dev/null
+++ b/skins/default/xmlfiles/displaymenudetailtext.xml
@@ -0,0 +1,99 @@
+<menudetailedtext x="0" y="0" width="100%" height="100%" fadetime="0">
+ <background>
+ <area x="0" y="0" width="100%" height="100%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ </background>
+ <header>
+ <area x="0" y="0" width="75%" height="10%" layer="2">
+ <drawtext x="5" valign="center" font="{light}" fontsize="50%" color="{clrWhite}" text="{title}" />
+ </area>
+ </header>
+ <datetime>
+ <area x="75%" y="0" width="12%" height="10%" layer="2">
+ <drawtext align="right" y="15%" font="{light}" fontsize="30%" color="{clrWhite}" text="{dayname}" />
+ <drawtext align="right" y="45%" font="{light}" fontsize="30%" color="{clrWhite}" text="{day}. {monthname}" />
+ </area>
+ <area x="87%" y="0" width="13%" height="10%" layer="2">
+ <drawtext align="center" valign="center" font="{light}" fontsize="60%" color="{clrWhite}" text="{time}" />
+ </area>
+ </datetime>
+ <!-- Available Variables colorbuttons:
+ {red1} true if red button is button 1
+ {red2} true if red button is button 2
+ {red3} true if red button is button 3
+ {red4} true if red button is button 4
+ {green1} true if green button is button 1
+ {green2} true if green button is button 2
+ {green3} true if green button is button 3
+ {green4} true if green button is button 4
+ {yellow1} true if yellow button is button 1
+ {yellow2} true if yellow button is button 2
+ {yellow3} true if yellow button is button 3
+ {yellow4} true if yellow button is button 4
+ {blue1} true if blue button is button 1
+ {blue2} true if blue button is button 2
+ {blue3} true if blue button is button 3
+ {blue4} true if blue button is button 4
+ {red} label of red button
+ {green} label of green button
+ {yellow} label of yellow button
+ {blue} label of blue button
+ -->
+ <colorbuttons>
+ <area x="0" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red1}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green1}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow1}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue1}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="25%" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red2}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green2}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow2}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue2}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="50%" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red3}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green3}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow3}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue3}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="75%" y="92%" width="25%" height="8%" layer="2">
+ <drawtext condition="{red4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red4}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green4}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow4}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue4}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ </colorbuttons>
+ <scrollbar>
+ <area x="98%" y="10%" width="2%" height="80%" layer="3">
+ <fill color="{clrWhite}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrWhite}" />
+ </area>
+ </scrollbar>
+
+ <!-- Available Variables in tab elements:
+ {text} detailed text
+ -->
+ <tab name="text" x="2%" y="10%" width="94%" height="80%" layer="2" scrollheight="{areaheight}/4">
+ <drawtextbox x="0" y="0" width="96%" font="{light}" fontsize="5%" color="{clrWhite}" text="{text}" />
+ </tab>
+</menudetailedtext> \ No newline at end of file
diff --git a/skins/default/xmlfiles/displaymenumain.xml b/skins/default/xmlfiles/displaymenumain.xml
new file mode 100644
index 0000000..a6cfd6b
--- /dev/null
+++ b/skins/default/xmlfiles/displaymenumain.xml
@@ -0,0 +1,276 @@
+<menumain x="0" y="0" width="100%" height="100%" fadetime="0">
+ <!--
+ static content of main menu, is only drawn once at main menu startup
+ -->
+ <background>
+ <!-- main menu background -->
+ <area x="0" y="0" width="71%" height="70%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <!-- datetime background -->
+ <area x="75%" y="0" width="25%" height="10%" layer="2">
+ <drawrectangle x="0" y="0" width="53%" height="100%" color="{clrTransBlueLight}" />
+ <drawrectangle x="53%" y="0" width="47%" height="100%" color="{clrTransBlack}" />
+ </area>
+ </background>
+ <!-- Available Variables header:
+ {title} title of current menu
+ {vdrversion} running VDR Version
+ -->
+ <header>
+ <area x="0" y="0" width="70%" height="7%" layer="2">
+ <drawtext x="10" valign="center" font="{light}" fontsize="100%" color="{clrWhite}" text="{title} {vdrversion}" />
+ </area>
+ </header>
+ <!-- Available Variables datetime:
+ {time} time in hh:mm
+ {day} day in digits
+ {dayleadingzero} day in digits with leading 0
+ {dayname} Full name of the day
+ {daynameshort} Short 3 char name of the day
+ {month} month in digits with leading 0
+ {monthname} Full name of the month
+ {monthnameshort} 3 letter abbrivation of month name
+ {year} year in yyyy
+ -->
+ <datetime>
+ <area x="75%" y="0" width="13%" height="10%" layer="3">
+ <drawtext align="right" y="0%" font="{light}" fontsize="55%" color="{clrWhite}" text="{dayname}" />
+ <drawtext align="right" y="45%" font="{light}" fontsize="55%" color="{clrWhite}" text="{day}. {monthnameshort}" />
+ </area>
+ <area x="88%" y="0" width="12%" height="10%" layer="3">
+ <drawtext align="center" valign="center" font="{light}" fontsize="100%" color="{clrWhite}" text="{time}" />
+ </area>
+ </datetime>
+
+ <!-- Available Variables colorbuttons:
+ {red1} true if red button is button 1
+ {red2} true if red button is button 2
+ {red3} true if red button is button 3
+ {red4} true if red button is button 4
+ {green1} true if green button is button 1
+ {green2} true if green button is button 2
+ {green3} true if green button is button 3
+ {green4} true if green button is button 4
+ {yellow1} true if yellow button is button 1
+ {yellow2} true if yellow button is button 2
+ {yellow3} true if yellow button is button 3
+ {yellow4} true if yellow button is button 4
+ {blue1} true if blue button is button 1
+ {blue2} true if blue button is button 2
+ {blue3} true if blue button is button 3
+ {blue4} true if blue button is button 4
+ {red} label of red button
+ {green} label of green button
+ {yellow} label of yellow button
+ {blue} label of blue button
+ -->
+ <colorbuttons>
+ <area x="0" y="63%" width="18%" height="7%" layer="2">
+ <drawtext condition="{red1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red1}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green1}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow1}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue1}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue1}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="18%" y="63%" width="17%" height="7%" layer="2">
+ <drawtext condition="{red2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red2}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green2}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow2}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue2}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue2}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="35%" y="63%" width="18%" height="7%" layer="2">
+ <drawtext condition="{red3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red3}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green3}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow3}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue3}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue3}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ <area x="53%" y="63%" width="17%" height="7%" layer="2">
+ <drawtext condition="{red4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle condition="{red4}" x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ <drawtext condition="{green4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle condition="{green4}" x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ <drawtext condition="{yellow4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle condition="{yellow4}" x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ <drawtext condition="{blue4}" x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle condition="{blue4}" x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ </colorbuttons>
+ <!-- Available Variables timers:
+ {numtimers} number of active timers (max. 15 timers will be displayed)
+ {numtimerconflicts} number of current timer conflicts
+
+ {timers[]} array with active timers (local and remote if remotetimers plugin is in use)
+ {timers[title]} title of timer
+ {timers[datetime]} date and time of timer
+ {timers[recording]} true if timer is recording currently
+ {timers[channelname]} name of channel for which timer is created
+ {timers[channelnumber]} number of channel
+ {timers[channelid]} ChannelID of channel
+ {timers[channellogoexists]} true if channel logo exists
+ -->
+ <timers>
+ <area x="0" y="75%" width="{areawidth}/8 - 5" height="25%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <area condition="not{numtimerconflicts}" x="0" y="75%" width="{areawidth}/8 - 5" height="25%" layer="2">
+ <drawtext align="center" y="15%" font="{light}" fontsize="50%" color="{clrWhite}" text="{numtimers}" />
+ <drawtext condition="eq({numtimers}, 0)||gt({numtimers}, 1)" name="timersheader" align="center" y="60%" font="{light}" fontsize="20%" color="{clrWhite}" text="{tr(activetimers)}" />
+ <drawtext condition="eq({numtimers}, 1)" name="timersheader" align="center" y="60%" font="{light}" fontsize="20%" color="{clrWhite}" text="{tr(activetimer)}" />
+ </area>
+ <area condition="{numtimerconflicts}" x="0" y="75%" width="{areawidth}/8 - 5" height="25%" layer="2">
+ <drawtext align="center" y="0" font="{light}" fontsize="50%" color="{clrWhite}" text="{numtimers}" />
+ <drawtext name="timersheader" align="center" y="45%" font="{light}" fontsize="20%" color="{clrWhite}" text="{tr(activetimers)}" />
+ <drawtext align="center" y="65%" font="{semibold}" fontsize="20%" color="{clrRed}" text="{numtimerconflicts} {tr(conflicts)}!" />
+ </area>
+
+ <area condition="gt({numtimers}, 0)" x="{areawidth}/8" y="75%" width="{areawidth}/8 - 5" height="25%" layer="1">
+ <fill color="{clrTransBlack}"/>
+ </area>
+ <area condition="gt({numtimers}, 1)" x="2*{areawidth}/8" y="75%" width="{areawidth}/8 - 5" height="25%" layer="1">
+ <fill color="{clrTransBlack}"/>
+ </area>
+ <area condition="gt({numtimers}, 2)" x="3*{areawidth}/8" y="75%" width="{areawidth}/8 - 5" height="25%" layer="1">
+ <fill color="{clrTransBlack}"/>
+ </area>
+ <area condition="gt({numtimers}, 3)" x="4*{areawidth}/8" y="75%" width="{areawidth}/8 - 5" height="25%" layer="1">
+ <fill color="{clrTransBlack}"/>
+ </area>
+ <area condition="gt({numtimers}, 4)" x="5*{areawidth}/8" y="75%" width="{areawidth}/8 - 5" height="25%" layer="1">
+ <fill color="{clrTransBlack}"/>
+ </area>
+ <area condition="gt({numtimers}, 5)" x="6*{areawidth}/8" y="75%" width="{areawidth}/8 - 5" height="25%" layer="1">
+ <fill color="{clrTransBlack}"/>
+ </area>
+ <area condition="gt({numtimers}, 6)" x="7*{areawidth}/8" y="75%" width="{areawidth}/8 - 5" height="25%" layer="1">
+ <fill color="{clrTransBlack}"/>
+ </area>
+ <area x="{areawidth}/8" y="75%" width="{areawidth}*0.875" height="25%" layer="2">
+ <loop name="timers" x="0" y="0" orientation="horizontal" columnwidth="{areawidth}/7" rowheight="{areaheight}" overflow="cut">
+ <drawrectangle condition="{timers[recording]}" x="0" y="0" width="{columnwidth}-5" height="{rowheight}" color="{clrRed}" />
+ <drawimage cache="true" name="logo" imagetype="channellogo" path="{timers[channelid]}" height="40%" align="center" y="10" />
+ <drawtextbox x="5" y="{height(logo)} + 10" width="{columnwidth}-10" align="center" maxlines="2" font="{light}" fontsize="15%" color="{clrWhite}" text="{timers[title]}" />
+ <drawtext align="center" y="75%" font="{light}" fontsize="20%" color="{clrWhite}" text="{timers[datetime]}" />
+ </loop>
+ </area>
+ </timers>
+
+ <!-- Available Variables discusage:
+ {freetime} available disc capacity in hh:mm
+ {freepercent} available disc capacity in percent
+ {usedpercent} used disc capacity in percent
+ {freegb} available disc capacity in gigabytes
+ {discalert} true if disc usage is > 95%
+ {vdrusagestring} localized VDR internal usage string
+ -->
+ <discusage>
+ <area x="75%" y="15%" width="25%" height="10%" layer="1">
+ <fill condition="not{discalert}" color="{clrTransBlack}"/>
+ <fill condition="{discalert}" color="{clrRed}"/>
+ </area>
+ <area x="75%" y="15%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="icon" path="ico_discusage" x="1%" valign="center" width="{areaheight}*0.9" height="{areaheight}*0.9"/>
+ <drawtext x="{areaheight}+10" y="0" font="{light}" fontsize="55%" color="{clrWhite}" text="{tr(disc)}: {freepercent}% {tr(free)}" />
+ <drawtext x="{areaheight}+10" y="45%" font="{light}" fontsize="55%" color="{clrWhite}" text="{freetime} {tr(hours)}" />
+ </area>
+ </discusage>
+
+ <!-- Available Variables devices:
+ {numdevices} number of available devices
+ {devices[]} array with available devices
+ {devices[num]} number of current device
+ {devices[type]} type of device (DVB-S, DVB-C, ...)
+ {devices[istuned]} true if device is currently tuned to a transponder
+ {devices[livetv]} true if device is currently playing livetv
+ {devices[recording]} true if device is currently recording
+ {devices[hascam]} true if device has a CAM
+ {devices[cam]} number of CAM
+ {devices[signalstrength]} signalstrength of devcie
+ {devices[signalquality]} signalstrength of devcie
+ {devices[channelnumber]} number of the currently tuned channel
+ {devices[channelname]} name of the currently tuned channel
+ {devices[channelid]} ID of the currently tuned channel
+ {devices[source]} source of the currently tuned channel
+ -->
+ <devices>
+ <area x="75%" y="40%" width="25%" height="{areaheight}/12 * {numdevices}" layer="1">
+ <fill color="{clrTransBlack}"/>
+ </area>
+ <area x="75%" y="40%" width="25%" height="{areaheight}/12 * {numdevices}" layer="2">
+ <loop name="devices" x="0" y="0" orientation="vertical" columnwidth="{areawidth}" rowheight="{areaheight} / {numdevices}" overflow="cut">
+ <drawtext name="label" x="5" y="0" font="{light}" fontsize="{rowheight}*0.4" color="{clrWhite}" text="{devices[num]}: {devices[type]}" />
+ <drawtext condition="{devices[hascam]}" x="{width(label)} + 15" y="0" font="{light}" fontsize="{rowheight}*0.40" color="{clrWhite}" text="(CAM {devices[cam]})" />
+ <drawtext condition="{devices[recording]} ++ {devices[livetv]}" align="right" y="0" font="{light}" fontsize="{rowheight}*0.40" color="{clrRed}" text="LiveTV, Recording ({devices[channelname]}) " />
+ <drawtext condition="{devices[recording]} ++ not{devices[livetv]}" align="right" y="0" font="{light}" fontsize="{rowheight}*0.40" color="{clrRed}" text="Recording ({devices[channelname]}) " />
+ <drawtext condition="not{devices[recording]} ++ {devices[livetv]}" align="right" y="0" font="{light}" fontsize="{rowheight}*0.40" color="{clrWhite}" text="LiveTV ({devices[channelname]}) " />
+ <drawrectangle condition="{devices[istuned]}" x="5" y="{rowheight}/3 + 5" width="{areawidth} * {devices[signalstrength]} / 100 - 10 * {devices[signalstrength]} / 100" height="{rowheight}/3 - 10" color="{clrTransWhite}" />
+ <drawrectangle condition="{devices[istuned]}" x="5" y="2*{rowheight}/3 + 5" width="{areawidth} * {devices[signalquality]} / 100 - 10 * {devices[signalquality]} / 100" height="{rowheight}/3 - 10" color="{clrTransWhite}" />
+ <drawtext condition="not{devices[istuned]}" align="center" y="{rowheight}/2" font="{light}" fontsize="{rowheight}*0.40" color="{clrWhite}" text="not tuned" />
+ </loop>
+ </area>
+ </devices>
+
+ <!-- Available Variables systemload:
+ {load} current system load
+ -->
+ <systemload>
+ <area x="75%" y="30%" width="25%" height="5%" layer="1">
+ <fill color="{clrTransBlack}"/>
+ </area>
+ <area x="75%" y="30%" width="25%" height="5%" layer="2">
+ <drawtext x="5" valign="center" font="{light}" fontsize="100%" color="{clrWhite}" text="System Load: {load}" />
+ </area>
+ </systemload>
+
+ <menuitems x="0" y="7%" orientation="vertical" width="70%" height="56%" align="center" numlistelements="8">
+ <!-- Available Variables main menu listelement:
+ {label} label of menu item
+ {number} number of menu item (or empty string if not set)
+ {icon} path of appropriate icon
+ {current} true if item is currently selected
+ {separator} true if item is a list separator
+ -->
+ <listelement>
+ <area x="0" width="60%" layer="2">
+ <fill condition="not{current}" color="{clrTransparent}" />
+ <fill condition="{current}" color="{clrTransBlueLight}" />
+ </area>
+ <areascroll scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="0" width="60%" layer="3">
+ <drawtext name="menutext" x="20" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{number} {label}" />
+ </areascroll>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables main menu currentelement:
+ {label} label of menu item
+ {number} number of menu item (or empty string if not set)
+ {icon} path of appropriate icon
+ -->
+ <currentelement delay="50" fadetime="0">
+ <area x="61%" y="22%" width="36%" height="52%" layer="2">
+ <fill color="{clrTransBlueLight}" />
+ </area>
+ <area x="61%" y="23%" width="36%" height="50%" layer="3">
+ <drawimage imagetype="menuicon" path="{icon}" align="center" valign="center" width="{areaheight} - 10" height="{areaheight} - 10"/>
+ </area>
+ </currentelement>
+ </menuitems>
+
+ <scrollbar>
+ <area x="68%" y="7%" width="2%" height="56%" layer="2">
+ <fill color="{clrWhite}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrWhite}" />
+ </area>
+ </scrollbar>
+</menumain>
diff --git a/skins/default/xmlfiles/displaymenurecordings.xml b/skins/default/xmlfiles/displaymenurecordings.xml
new file mode 100644
index 0000000..f7d1097
--- /dev/null
+++ b/skins/default/xmlfiles/displaymenurecordings.xml
@@ -0,0 +1,85 @@
+<menurecordings x="0" y="0" width="100%" height="100%" fadetime="0">
+ <menuitems x="0" y="10%" orientation="vertical" width="100%" height="82%" align="center" numlistelements="16">
+ <!-- Available Variables recordings menu listelement:
+ {name} Name of recording
+ {date} Date of recording
+ {time} Time of recording
+ {duration} real duration of recording in minutes
+ {durationevent} duration of corresponding event in minutes
+ {current} true if item is currently selected
+ {new} true if recording is new
+ {cutted} true if recording is cutted
+ {folder} true if item is a folder
+ {numrecordingsfolder} if item is a folder, number of recordings in this folder
+ {newrecordingsfolder} if item is a folder, number of new recordings in this folder
+ {hasposterthumbnail} true if a scraped poster thumbnail is available for recording
+ {thumbnailbwidth} width of scraped poster thumbnail
+ {thumbnailheight} height of scraped poster thumbnail
+ {thumbnailpath} absolute path of scraped poster thumbnail
+ -->
+ <listelement>
+ <!-- Background -->
+ <area x="1%" width="58%" layer="2">
+ <fill condition="not{current}" color="{clrTransparent}" />
+ <fill condition="{current}" color="{clrTransBlueLight}" />
+ <fill condition="{separator}" color="{clrSemiTransBlack}" />
+ </area>
+ <!-- recording folder -->
+ <area condition="{folder}" x="1%" width="58%" layer="2">
+ <drawimage name="foldericon" imagetype="icon" path="ico_recfolder" x="10" width="0.9*{areaheight} * 92 / 136" height="0.9*{areaheight}" valign="center" />
+ <drawtext x="{width(foldericon)} + 20" valign="center" font="{light}" fontsize="95%" color="{clrWhite}" text="{name} ({numrecordingsfolder}, {newrecordingsfolder} new)" />
+ </area>
+ <!-- recording item -->
+ <area condition="not{folder}" x="1%" width="58%" layer="2">
+ <drawtext x="10" valign="center" font="{light}" fontsize="85%" color="{clrWhite}" text="{date} {time}" />
+ <drawtext x="35%" width="60%" valign="center" font="{light}" fontsize="85%" color="{clrWhite}" text="{name}" />
+ <drawimage condition="{new}" name="new" imagetype="icon" path="ico_recnew" x="{areawidth} - {areaheight}" width="0.9*{areaheight}" height="0.9*{areaheight}" valign="center" />
+ <drawimage condition="{new}++{cutted}" imagetype="icon" path="ico_cutted" x="{areawidth} - 2*{areaheight}" width="0.9*{areaheight}" height="0.9*{areaheight}" valign="center" />
+ <drawimage condition="not{new}++{cutted}" imagetype="icon" path="ico_cutted" x="{areawidth} - {areaheight}" width="0.9*{areaheight}" height="0.9*{areaheight}" valign="center" />
+ </area>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables channels menu currentelement:
+ {name} Name of recording
+ {shorttext} Short Text of recording
+ {description} Descrption of recording
+ {date} Date of recording
+ {time} Time of recording
+ {duration} real duration of recording in minutes
+ {durationevent} duration of corresponding event in minutes
+ {new} true if recording is new
+ {cutted} true if recording is cutted
+ {folder} true if item is a folder
+ {numrecordingsfolder} if item is a folder, number of recordings in this folder
+ {newrecordingsfolder} if item is a folder, number of new recordings in this folder
+ {hasposter} true if a scraped poster is available for recording
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ -->
+ <currentelement delay="500" fadetime="0">
+ <area x="63%" y="0" width="36%" height="100%" layer="2">
+ <!-- header -->
+ <drawtext name="title" x="1%" y="0" width="98%" font="{semibold}" fontsize="8%" color="{clrWhite}" text="{name}" />
+ <drawtext name="shorttext" x="1%" y="{height(title)}" width="98%" font="{semibold}" fontsize="6%" color="{clrWhite}" text="{shorttext}" />
+ <drawtext name="datetime" x="1%" y="{posy(shorttext)} + {height(shorttext)}" font="{light}" fontsize="5%" color="{clrWhite}" text="{date} {time}, {duration} min" />
+ <!-- scraper poster -->
+ <drawimage condition="{hasposter}" name="poster" imagetype="image" path="{posterpath}" x="1%" y="{posy(datetime)} + {height(datetime)} + 20" width="{areawidth}/3" height="{areawidth}/3 * {posterheight} / {posterwidth}"/>
+ <!-- description -->
+ <drawtextbox condition="{hasposter}" x="1%" y="{posy(poster)}" width="98%" height="{areaheight} - {posy(poster)}" float="topleft" floatwidth="{width(poster)} + 10" floatheight="{height(poster)} + 10" font="{light}" fontsize="6%" color="{clrWhite}" text="{description}" />
+ <drawtextbox condition="not{hasposter}" x="1%" y="{posy(poster)}" width="98%" height="{areaheight} - {posy(poster)}" font="{light}" fontsize="6%" color="{clrWhite}" text="{description}" />
+ </area>
+ </currentelement>
+ </menuitems>
+ <!-- Available Variables colorbuttons:
+ {height} height in one-tenth of a percent of total height
+ {offset} offset from top in one-tenth of a percent of total height
+ -->
+ <scrollbar>
+ <area x="60%" y="10%" width="2%" height="82%" layer="3">
+ <fill color="{clrWhite}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrWhite}" />
+ </area>
+ </scrollbar>
+</menurecordings> \ No newline at end of file
diff --git a/skins/default/xmlfiles/displaymenuschedules.xml b/skins/default/xmlfiles/displaymenuschedules.xml
new file mode 100644
index 0000000..eb856c8
--- /dev/null
+++ b/skins/default/xmlfiles/displaymenuschedules.xml
@@ -0,0 +1,179 @@
+<menuschedules x="0" y="0" width="100%" height="100%" fadetime="0">
+ <!-- Available Variables header:
+ {title} title of current menu
+ {vdrversion} running VDR Version
+ {channelnumber} Number of Channel of current event
+ {channelname} Name of current Channel of current event
+ {channellogoexists} true if a channel logo exists
+ {channelid} ChannelID as path to display channel logo
+ {whatson} true if menu "What's on" is displayed
+ {whatsonnow} true if menu "What's on now" is displayed
+ {whatsonnext} true if menu "What's on next" is displayed
+ -->
+ <header>
+ <area x="0" y="0" width="38%" height="10%" layer="2">
+ <drawtext condition="{whatsonnow}||{whatsonnext}" x="5" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{title}" />
+ <drawimage name="logo" condition="{whatson}" imagetype="channellogo" path="{channelid}" x="0" height="100%" align="left" valign="center" />
+ <drawtext condition="{whatson}" x="{width(logo)}+20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{channelnumber} - {channelname}" />
+ </area>
+ </header>
+
+ <menuitems x="0" y="10%" orientation="vertical" width="100%" height="82%" align="center" numlistelements="16">
+ <!-- Available Variables schedules menu listelement:
+ {title} title of event
+ {shorttext} shorttext of event
+ {start} event start time in hh::mm
+ {stop} event stop time
+ {day} day of current event
+ {date} date of current event in dd.mm.yy
+ {running} true if event is currently running
+ {elapsed} elapsed time of event, if not running 0
+ {duration} duration of event
+ {current} true if item is currently selected
+ {separator} true if item is a list separator
+ {channelid} ChannelID as path to display channel logo
+ {whatson} true if menu "What's on" is displayed
+ {whatsonnow} true if menu "What's on now" is displayed
+ {whatsonnext} true if menu "What's on next" is displayed
+ {timerpartitial} true if partitial timer is set for the event
+ {timerfull} true if full timer is set for the event
+ -->
+ <listelement>
+ <!-- Background -->
+ <area x="1%" width="58%" layer="2">
+ <fill condition="not{current}" color="{clrTransparent}" />
+ <fill condition="{current}" color="{clrTransBlueLight}" />
+ <fill condition="{separator}" color="{clrSemiTransBlack}" />
+ </area>
+ <!-- WHATSON -->
+ <areascroll condition="not{separator}++{whatson}++not{running}" scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="1%" width="58%" layer="3">
+ <drawtext name="menutext" x="20" valign="center" font="{light}" fontsize="95%" color="{clrWhite}" text="{start} {title}" />
+ </areascroll>
+ <areascroll condition="not{separator}++{whatson}++{running}" scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="1%" width="48%" layer="3">
+ <drawtext name="menutext" x="20" valign="center" font="{light}" fontsize="95%" color="{clrWhite}" text="{start} {title}" />
+ </areascroll>
+ <area condition="not{separator}++{whatson}" x="1%" width="58%" layer="3">
+ <drawimage condition="{timerfull}" imagetype="icon" path="ico_activetimer" x="{areawidth} - 0.9*{areaheight} - 10" width="0.9*{areaheight}" height="0.9*{areaheight}" valign="center" />
+ <drawimage condition="{timerpartitial}" imagetype="icon" path="ico_activetimer" x="{areawidth} - 0.5*{areaheight} - 10" width="0.5*{areaheight}" height="0.5*{areaheight}" valign="center" />
+ <drawrectangle condition="{running}" x="{areawidth}*0.85 - 10" y="{areaheight}/3" width="{areawidth}*0.15" height="{areaheight}/3" color="{clrWhite}" />
+ <drawrectangle condition="{running}" x="{areawidth}*0.85 - 8" y="{areaheight}/3 + 2" width="{areawidth}*0.15 - 4" height="{areaheight}/3 - 4" color="{clrTransparent}" />
+ <drawrectangle condition="{running}" x="{areawidth}*0.85 - 6" y="{areaheight}/3 + 4" width="{areawidth}*0.15 * {elapsed} / {duration} - 8" height="{areaheight}/3 - 8" color="{clrWhite}" />
+ </area>
+ <!-- WHATSONNOW -->
+ <area condition="not{separator}++{whatsonnow}" x="1%" width="6%" layer="3">
+ <drawimage name="logo" imagetype="channellogo" path="{channelid}" x="10" height="100%" valign="center" />
+ </area>
+ <area condition="not{separator}++{whatsonnow}++{running}" x="8%" width="7%" layer="3">
+ <drawrectangle condition="{current}" x="0" y="{areaheight}/3" width="{areawidth}" height="{areaheight}/3" color="{clrWhite}" />
+ <drawrectangle condition="not{current}" x="0" y="{areaheight}/3" width="{areawidth}" height="{areaheight}/3" color="{clrTransBlueLight}" />
+ <drawrectangle x="2" y="{areaheight}/3 + 2" width="{areawidth} - 4" height="{areaheight}/3 - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="{areaheight}/3 + 4" width="{areawidth} * {elapsed} / {duration} - 8" height="{areaheight}/3 - 8" color="{clrWhite}" />
+ </area>
+ <area condition="not{separator}++{whatsonnow}++{timerfull}" x="53%" width="6%" layer="4">
+ <drawimage imagetype="icon" path="ico_activetimer" x="{areawidth} - 0.9*{areaheight} - 10" width="0.9*{areaheight}" height="0.9*{areaheight}" valign="center" />
+ </area>
+ <area condition="not{separator}++{whatsonnow}++{timerpartitial}" x="53%" width="6%" layer="5">
+ <drawimage imagetype="icon" path="ico_activetimer" x="{areawidth} - 0.5*{areaheight} - 10" width="0.5*{areaheight}" height="0.5*{areaheight}" valign="center" />
+ </area>
+ <areascroll condition="not{separator}++{whatsonnow}" scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="15%" width="44%" layer="4">
+ <drawtext name="menutext" x="10" valign="center" font="{light}" fontsize="95%" color="{clrWhite}" text="{start} {title}" />
+ </areascroll>
+ <!-- WHATSONNEXT -->
+ <area condition="not{separator}++{whatsonnext}" x="1%" width="6%" layer="3">
+ <drawimage name="logo" imagetype="channellogo" path="{channelid}" x="10" height="100%" valign="center" />
+ </area>
+ <area condition="not{separator}++{whatsonnext}++{timerfull}" x="53%" width="6%" layer="4">
+ <drawimage imagetype="icon" path="ico_activetimer" x="{areawidth} - 0.9*{areaheight} - 10" width="0.9*{areaheight}" height="0.9*{areaheight}" valign="center" />
+ </area>
+ <area condition="not{separator}++{whatsonnext}++{timerpartitial}" x="53%" width="6%" layer="5">
+ <drawimage imagetype="icon" path="ico_activetimer" x="{areawidth} - 0.5*{areaheight} - 10" width="0.5*{areaheight}" height="0.5*{areaheight}" valign="center" />
+ </area>
+ <areascroll condition="not{separator}++{whatsonnext}" scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="7%" width="52%" layer="4">
+ <drawtext name="menutext" x="10" valign="center" font="{light}" fontsize="95%" color="{clrWhite}" text="{start} {title}" />
+ </areascroll>
+ <!-- Separator -->
+ <area condition="{separator}" x="0" width="68%" layer="3">
+ <drawtext x="20" valign="center" font="{light}" fontsize="95%" color="{clrBlueLight}" text="{title}" />
+ </area>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables schedules menu currentelement:
+ {title} title of event
+ {shorttext} shorttext of event
+ {description} detailed description of event
+ {start} event start time in hh::mm
+ {stop} event stop time
+ {day} day of current event
+ {date} date of current event in dd.mm.yy
+ {running} true if event is currently running
+ {elapsed} elapsed time of event, if not running 0
+ {duration} duration of event
+ {channelid} ChannelID as path to display channel logo
+ {hasposter} true if a scraped poster is available for this element
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {timerpartitial} true if partitial timer is set for the event
+ {timerfull} true if full timer is set for the event
+ {whatson} true if menu "What's on" is displayed
+ {whatsonnow} true if menu "What's on now" is displayed
+ {whatsonnext} true if menu "What's on next" is displayed
+ {schedule[]} array with next 10 schedules, only for whatsonnow and whatsonnext
+ {schedule[title]} title of event
+ {schedule[shorttext]} shorttext of event
+ {schedule[start]} start time of event in hh:mm
+ {schedule[stop]} stop time of event in hh:mm
+ -->
+ <currentelement delay="500" fadetime="0">
+ <area condition="{whatson}" x="63%" y="0" width="36%" height="100%" layer="2">
+ <!-- title -->
+ <drawtext align="center" y="0" font="{semibold}" width="{areawidth}-20" fontsize="8%" color="{clrWhite}" text="{title}" />
+ <!-- progress bar if event is running -->
+ <drawtext condition="{running}" name="start" x="{areawidth}/4 - {width(start)}" y="{areaheight}/16 + 20" font="{light}" fontsize="{areaheight}/18" color="{clrWhite}" text="{start}" />
+ <drawtext condition="{running}" name="stop" x="{areawidth}*3/4" y="{areaheight}/16 + 20" font="{light}" fontsize="{areaheight}/18" color="{clrWhite}" text="{stop}" />
+ <drawrectangle condition="{running}" x="{areawidth}/4+10" y="{areaheight}/16 + 20 + {areaheight}/36" width="{areawidth}/2 - 20" height="1" color="{clrWhite}" />
+ <drawrectangle condition="{running}" x="{areawidth}/4+10" y="{areaheight}/16 + 20 + {areaheight}/36 -2" width="{areawidth}/2 * {elapsed} / {duration} - 20 * {elapsed} / {duration}" height="5" color="{clrWhite}" />
+ <!-- start and stop if event is not running -->
+ <drawtext condition="not{running}" x="10" y="{areaheight}/18 + 20" font="{light}" fontsize="{areaheight}/20" color="{clrWhite}" text="{start} - {stop} ({duration} min)" />
+ <!-- scraper poster -->
+ <drawimage condition="{hasposter}" name="poster" imagetype="image" path="{posterpath}" x="10" y="{posy(start)} + {height(start)} + 20" width="{areawidth}/3" height="{areawidth}/3 * {posterheight} / {posterwidth}"/>
+ <!-- description -->
+ <drawtextbox condition="{hasposter}" x="10" y="{posy(poster)}" width="99%" height="{areaheight} - {posy(poster)}" float="topleft" floatwidth="{width(poster)} + 10" floatheight="{height(poster)} + 20" font="{light}" fontsize="{areaheight}/20" color="{clrWhite}" text="{description}" />
+ <drawtextbox condition="not{hasposter}" x="10" y="{posy(poster)}" width="99%" height="{areaheight} - {posy(poster)}" font="{light}" fontsize="{areaheight}/20" color="{clrWhite}" text="{description}" />
+ </area>
+ <area condition="{whatsonnow}||{whatsonnext}" x="63%" y="0" width="36%" height="85%" layer="2">
+ <!-- title -->
+ <drawtext align="center" y="0" font="{semibold}" width="{areawidth}-20" fontsize="10%" color="{clrWhite}" text="{title}" />
+ <!-- progress bar if event is running -->
+ <drawtext condition="{running}" name="start" x="{areawidth}/4 - {width(start)}" y="{areaheight}/16 + 15" font="{light}" fontsize="{areaheight}/15" color="{clrWhite}" text="{start}" />
+ <drawtext condition="{running}" name="stop" x="{areawidth}*3/4" y="{areaheight}/16 + 15" font="{light}" fontsize="{areaheight}/15" color="{clrWhite}" text="{stop}" />
+ <drawrectangle condition="{running}" x="{areawidth}/4+10" y="{areaheight}/16 + 15 + {areaheight}/30" width="{areawidth}/2 - 20" height="1" color="{clrWhite}" />
+ <drawrectangle condition="{running}" x="{areawidth}/4+10" y="{areaheight}/16 + 15 + {areaheight}/30 -2" width="{areawidth}/2 * {elapsed} / {duration} - 20 * {elapsed} / {duration}" height="5" color="{clrWhite}" />
+ <!-- start and stop if event is not running -->
+ <drawtext condition="not{running}" x="10" y="{areaheight}/18 + 15" font="{light}" fontsize="{areaheight}/20" color="{clrWhite}" text="{start} - {stop} ({duration} min)" />
+ <!-- scraper poster -->
+ <drawimage condition="{hasposter}" name="poster" imagetype="image" path="{posterpath}" x="10" y="{posy(start)} + {height(start)} + 10" width="{areawidth}/3" height="{areawidth}/3 * {posterheight} / {posterwidth}"/>
+ <!-- description -->
+ <drawtextbox condition="{hasposter}" x="10" y="{posy(poster)}" width="99%" height="{areaheight} - {posy(poster)}" float="topleft" floatwidth="{width(poster)} + 10" floatheight="{height(poster)} + 10" font="{light}" fontsize="{areaheight}/18" color="{clrWhite}" text="{description}" />
+ <drawtextbox condition="not{hasposter}" x="10" y="{posy(poster)}" width="99%" height="{areaheight} - {posy(poster)}" font="{light}" fontsize="{areaheight}/18" color="{clrWhite}" text="{description}" />
+ </area>
+ <areascroll condition="{whatsonnow}||{whatsonnext}" mode="forthandback" orientation="vertical" delay="1000" scrollspeed="medium" x="63%" y="85%" width="36%" height="15%" layer="2">
+ <drawtext x="10" y="0" font="{semibold}" fontsize="30%" color="{clrWhite}" text="Next Schedules:" />
+ <loop name="schedule" x="0" y="{areaheight}/4 + 5" orientation="vertical">
+ <drawtext x="10" font="{light}" width="{areawidth}-20" fontsize="30%" color="{clrWhite}" text="{schedule[start]} {schedule[title]}" />
+ </loop>
+ </areascroll>
+ </currentelement>
+ </menuitems>
+ <!-- Available Variables scrollbar:
+ {height} height in one-tenth of a percent of total height
+ {offset} offset from top in one-tenth of a percent of total height
+ -->
+ <scrollbar>
+ <area x="60%" y="10%" width="2%" height="82%" layer="3">
+ <fill color="{clrWhite}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrWhite}" />
+ </area>
+ </scrollbar>
+</menuschedules> \ No newline at end of file
diff --git a/skins/default/xmlfiles/displaymenusetup.xml b/skins/default/xmlfiles/displaymenusetup.xml
new file mode 100644
index 0000000..b5b8fb4
--- /dev/null
+++ b/skins/default/xmlfiles/displaymenusetup.xml
@@ -0,0 +1,107 @@
+<menusetup x="0" y="0" width="100%" height="100%" fadetime="0">
+ <!--
+ static content of main menu, is only drawn once at main menu startup
+ -->
+ <background>
+ <area x="0" y="0" width="100%" height="100%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <area x="84%" y="0" width="16%" height="7%" layer="2">
+ <drawrectangle x="0" y="0" width="52%" height="100%" color="{clrTransBlueLight}" />
+ </area>
+ </background>
+ <!-- Available Variables header:
+ {title} title of current menu
+ {vdrversion} running VDR Version
+ -->
+ <header>
+ <area x="0" y="0" width="70%" height="7%" layer="2">
+ <drawtext x="10" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{title}" />
+ </area>
+ </header>
+ <!-- Available Variables datetime:
+ {time} time in hh:mm
+ {day} day in digits
+ {dayleadingzero} day in digits with leading 0
+ {dayname} Full name of the day
+ {daynameshort} Short 3 char name of the day
+ {month} month in digits with leading 0
+ {monthname} Full name of the month
+ {year} year in yyyy
+ -->
+ <datetime>
+ <area x="84%" y="0" width="8%" height="7%" layer="3">
+ <drawtext align="right" y="0%" font="{light}" fontsize="55%" color="{clrWhite}" text="{dayname}" />
+ <drawtext align="right" y="45%" font="{light}" fontsize="55%" color="{clrWhite}" text="{day}. {monthname}" />
+ </area>
+ <area x="92%" y="0" width="8%" height="7%" layer="3">
+ <drawtext align="center" valign="center" font="{light}" fontsize="100%" color="{clrWhite}" text="{time}" />
+ </area>
+ </datetime>
+
+ <!-- Available Variables colorbuttons:
+ {red} label of red button
+ {green} label of green button
+ {yellow} label of yellow button
+ {blue} label of blue button
+ -->
+ <colorbuttons>
+ <area x="0" y="93%" width="25%" height="7%" layer="2">
+ <drawtext x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{red}" />
+ <drawrectangle x="0" y="0" width="10" height="100%" color="{clrRed}" />
+ </area>
+ <area x="25%" y="93%" width="25%" height="7%" layer="2">
+ <drawtext x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{green}" />
+ <drawrectangle x="0" y="0" width="10" height="100%" color="{clrGreen}" />
+ </area>
+ <area x="50%" y="93%" width="25%" height="7%" layer="2">
+ <drawtext x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{yellow}" />
+ <drawrectangle x="0" y="0" width="10" height="100%" color="{clrYellow}" />
+ </area>
+ <area x="75%" y="93%" width="25%" height="7%" layer="2">
+ <drawtext x="20" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{blue}" />
+ <drawrectangle x="0" y="0" width="10" height="100%" color="{clrBlue}" />
+ </area>
+ </colorbuttons>
+
+ <menuitems x="0" y="7%" orientation="vertical" width="98%" height="86%" align="center" numlistelements="10">
+ <!-- Available Variables setup menu listelement:
+ {label} label of menu item
+ {number} number of menu item (or empty string if not set)
+ {icon} path of appropriate icon
+ {current} true if item is currently selected
+ {separator} true if item is a list separator
+ -->
+ <listelement>
+ <area x="0" width="60%" layer="2">
+ <fill condition="not{current}" color="{clrTransparent}" />
+ <fill condition="{current}" color="{clrTransBlueLight}" />
+ </area>
+ <areascroll scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="0" width="60%" layer="3">
+ <drawtext name="menutext" x="20" valign="center" font="{light}" fontsize="90%" color="{clrWhite}" text="{number} {label}" />
+ </areascroll>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables main menu currentelement:
+ {label} label of menu item
+ {number} number of menu item (or empty string if not set)
+ {icon} path of appropriate icon
+ -->
+ <currentelement delay="50" fadetime="0">
+ <area x="61%" y="30%" width="37%" height="36%" layer="2">
+ <fill color="{clrTransBlueLight}" />
+ </area>
+ <area x="61%" y="30%" width="37%" height="36%" layer="3">
+ <drawimage imagetype="menuicon" path="{icon}" align="center" valign="center" width="{areaheight} - 10" height="{areaheight} - 10"/>
+ </area>
+ </currentelement>
+ </menuitems>
+
+ <scrollbar>
+ <area x="98%" y="7%" width="2%" height="86%" layer="2">
+ <fill color="{clrWhite}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrWhite}" />
+ </area>
+ </scrollbar>
+</menusetup>
diff --git a/skins/default/xmlfiles/displaymenutimers.xml b/skins/default/xmlfiles/displaymenutimers.xml
new file mode 100644
index 0000000..60b66a5
--- /dev/null
+++ b/skins/default/xmlfiles/displaymenutimers.xml
@@ -0,0 +1,90 @@
+<menutimers x="0" y="0" width="100%" height="100%" fadetime="0">
+ <menuitems x="0" y="10%" orientation="vertical" width="100%" height="82%" align="center" numlistelements="16">
+ <!-- Available Variables channels menu listelement:
+ {title} Title of Timer
+ {timerstart} Start Time of Timer in hh::mm
+ {timerstop} End Time of Timer in hh::mm
+ {day} Day (numerical)
+ {dayname} Day, for repeating timers days where timer is active
+ {channelname} Name of channel which is set for the timer
+ {channelid} ID of channel which is set for the timer (for dispalying channel logo)
+ {channelnumber} Number of channel which is set for the timer
+ {eventtitle} Title of corresponding event
+ {eventstart} Start Time of corresponding event in hh::mm
+ {eventstop} Stop Time of corresponding event in hh::mm
+ {current} true if item is currently selected
+ {flagactive} true if timer is active
+ {flaginstant} true if timer is an instant timer
+ {flagvps} true if timer uses VPS
+ {flagrecording} true if is recording currently
+ {flagpending} true if timer is pending
+ -->
+ <listelement>
+ <!-- Background -->
+ <area x="1%" width="58%" layer="2">
+ <fill condition="not{current}" color="{clrTransparent}" />
+ <fill condition="{current}" color="{clrTransBlueLight}" />
+ </area>
+ <area x="1%" width="58%" layer="2">
+ <drawimage condition="{flagactive}" name="active" imagetype="icon" path="ico_timer_active" x="0" width="0.9*{areaheight}" height="0.9*{areaheight}" valign="center" />
+ <drawimage condition="not{flagactive}" name="active" imagetype="icon" path="ico_timer_inactive" x="0" width="0.9*{areaheight}" height="0.9*{areaheight}" valign="center" />
+ <drawimage condition="{flagrecording}" name="active" imagetype="icon" path="ico_timer_recording" x="0" width="0.9*{areaheight}" height="0.9*{areaheight}" valign="center" />
+ </area>
+ <areascroll scrollelement="timertext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="5%" width="54%" layer="3">
+ <drawtext name="timertext" x="10" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{dayname} {day}. {timerstart} - {timerstop}: {title}" />
+ </areascroll>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables channels menu currentelement:
+ {title} Title of Timer
+ {timerstart} Start Time of Timer in hh::mm
+ {timerstop} End Time of Timer in hh::mm
+ {day} Day (numerical)
+ {dayname} Day, for repeating timers days where timer is active
+ {channelname} Name of channel which is set for the timer
+ {channelid} ID of channel which is set for the timer (for dispalying channel logo)
+ {channelnumber} Number of channel which is set for the timer
+ {eventtitle} Title of corresponding event
+ {eventstart} Start Time of corresponding event in hh::mm
+ {eventstop} Stop Time of corresponding event in hh::mm
+ {eventshorttext} Short Text corresponding event
+ {eventdescription} Description corresponding event
+ {hasposter} true if a scraped poster is available for event
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {flagactive} true if timer is active
+ {flaginstant} true if timer is an instant timer
+ {flagvps} true if timer uses VPS
+ {flagrecording} true if is recording currently
+ {flagpending} true if timer is pending
+ -->
+ <currentelement delay="500" fadetime="0">
+ <area x="63%" y="0" width="36%" height="15%" layer="2">
+ <drawimage name="logo" imagetype="channellogo" path="{channelid}" x="10" y="0" height="100%" />
+ <drawtext name="channum" x="{width(logo)} + 20" y="{areaheight}/6" width="{areawidth} - {width(logo)} - 30" font="{light}" fontsize="40%" color="{clrWhite}" text="Channel No. {channelnumber}" />
+ <drawtext name="channame" x="{width(logo)} + 20" y="{areaheight}/3 + {areaheight}/6" width="{areawidth} - {width(logo)} - 30" font="{semibold}" fontsize="40%" color="{clrWhite}" text="{channelname}" />
+ </area>
+ <area x="63%" y="15%" width="36%" height="70%" layer="2">
+ <!-- title -->
+ <drawtext name="title" align="center" y="0" font="{semibold}" width="{areawidth}-20" fontsize="{areaheight}/10" color="{clrWhite}" text="{eventtitle}" />
+ <!-- scraper poster -->
+ <drawimage condition="{hasposter}" name="poster" imagetype="image" path="{posterpath}" x="10" y="{posy(title)} + {height(title)} + 10" width="{areawidth}/3" height="{areawidth}/3 * {posterheight} / {posterwidth}"/>
+ <!-- description -->
+ <drawtextbox condition="{hasposter}" x="10" y="{posy(poster)}" width="99%" height="{areaheight} - {posy(poster)}" float="topleft" floatwidth="{width(poster)} + 10" floatheight="{height(poster)} + 20" font="{light}" fontsize="{areaheight}/14" color="{clrWhite}" text="{eventdescription}" />
+ <drawtextbox condition="not{hasposter}" x="10" y="{posy(poster)}" width="99%" height="{areaheight} - {posy(poster)}" font="{light}" fontsize="{areaheight}/14" color="{clrWhite}" text="{eventdescription}" />
+ </area>
+ </currentelement>
+ </menuitems>
+ <!-- Available Variables colorbuttons:
+ {height} height in one-tenth of a percent of total height
+ {offset} offset from top in one-tenth of a percent of total height
+ -->
+ <scrollbar>
+ <area x="60%" y="10%" width="2%" height="82%" layer="3">
+ <fill color="{clrWhite}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrWhite}" />
+ </area>
+ </scrollbar>
+</menutimers> \ No newline at end of file
diff --git a/skins/default/xmlfiles/displaymessage.xml b/skins/default/xmlfiles/displaymessage.xml
new file mode 100644
index 0000000..01fbbdd
--- /dev/null
+++ b/skins/default/xmlfiles/displaymessage.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displaymessage SYSTEM "../../dtd/displaymessage.dtd">
+
+<displaymessage x="5%" y="80%" width="90%" height="15%" fadetime="{fadeTime}">
+ <background>
+ <area x="0" y="0" width="100%" height="100%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ </background>
+
+ <!-- Available Variables message:
+ {text} message text
+ {status} true if message is a status message
+ {info} true if message is a info message
+ {warning} true if message is a warn message
+ {error} true if message is a error message
+ -->
+ <message>
+ <area x="0" y="0" width="100%" height="100%" layer="2">
+ <drawrectangle condition="{status}" x="20" y="0" width="20" height="100%" color="{clrGreen}" />
+ <drawrectangle condition="{info}" x="20" y="0" width="20" height="100%" color="{clrBlue}" />
+ <drawrectangle condition="{warning}" x="20" y="0" width="20" height="100%" color="{clrYellow}" />
+ <drawrectangle condition="{error}" x="20" y="0" width="20" height="100%" color="{clrRed}" />
+ <drawtext align="center" valign="center" width="{areawidth} - 80" font="{light}" fontsize="50%" color="{clrWhite}" text="{text}" />
+ </area>
+ </message>
+</displaymessage>
diff --git a/skins/default/xmlfiles/displayreplay.xml b/skins/default/xmlfiles/displayreplay.xml
new file mode 100644
index 0000000..0bf81a2
--- /dev/null
+++ b/skins/default/xmlfiles/displayreplay.xml
@@ -0,0 +1,231 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displayreplay SYSTEM "../../dtd/displayreplay.dtd">
+
+<displayreplay x="0" y="0" width="100%" height="100%" fadetime="{fadeTime}">
+ <background>
+ <!-- background infobar -->
+ <area x="0" y="80%" width="100%" height="20%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <!-- background datetime -->
+ <area x="70%" y="0" width="30%" height="13%" layer="1">
+ <fill color="{clrTransBlack}" />
+ <drawrectangle x="0" y="0" width="45%" height="100%" color="{clrTransBlueLight}" />
+ </area>
+ </background>
+
+ <backgroundmodeonly>
+ <!-- background small infobar -->
+ <area x="25%" y="85%" width="50%" height="10%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <!-- background datetime -->
+ <area x="70%" y="0" width="30%" height="13%" layer="1">
+ <fill color="{clrTransBlack}" />
+ <drawrectangle x="0" y="0" width="45%" height="100%" color="{clrTransBlueLight}" />
+ </area>
+ </backgroundmodeonly>
+
+ <!-- Available Variables datetime:
+ {time} time in hh:mm
+ {day} day in digits
+ {dayleadingzero} day in digits with leading 0
+ {dayname} Full name of the day
+ {daynameshort} Short 3 char name of the day
+ {month} month in digits with leading 0
+ {monthname} Full name of the month
+ {monthnameshort} 3 letter abbrivation of month name
+ {year} year in yyyy
+ -->
+ <datetime>
+ <area x="70%" y="0" width="13%" height="13%" layer="2">
+ <drawtext align="right" y="0" font="{light}" fontsize="50%" color="{clrWhite}" text="{dayname}" />
+ <drawtext align="right" y="48%" font="{light}" fontsize="50%" color="{clrWhite}" text="{day}. {monthnameshort}" />
+ </area>
+ <area x="85%" y="0" width="13%" height="13%" layer="2">
+ <drawtext align="center" valign="center" font="{light}" fontsize="100%" color="{clrWhite}" text="{time}" />
+ </area>
+ </datetime>
+
+ <!-- Available Variables scrapercontent:
+ {mediapath} Full Path of Poster or Banner to use in image path attribute
+ {mediawidth} width of image in pixel
+ {mediaheight} height of image in pixel
+ {isbanner} true if image is a banner, false if it is a poster
+ -->
+ <scrapercontent>
+ <area condition="{isbanner}" x="0" y="0" width="{areaheight}*0.13*{mediawidth}/{mediaheight}" height="13%" layer="2">
+ <drawimage imagetype="image" path="{mediapath}" align="center" valign="center" width="{areawidth}" height="{areaheight}"/>
+ </area>
+ <area condition="not{isbanner}" x="0" y="0" width="{areaheight}*0.5*{mediawidth}/{mediaheight}" height="50%" layer="2">
+ <drawimage imagetype="image" path="{mediapath}" x="5" y="5" width="{areawidth}-10" height="{areaheight}-10"/>
+ </area>
+ </scrapercontent>
+
+ <!-- Available Variables rectitle:
+ {rectitle} Title of Recording
+ {recsubtitle} Subtitle of the Recording
+ {recdate} Date Recording in dd.mm.yy
+ {rectime} Time of Recording in hh:mm
+ -->
+ <rectitle>
+ <area x="1%" y="80%" width="69%" height="8%" layer="2">
+ <drawtext x="0" name="title" valign="center" width="{areawidth}" font="{semibold}" fontsize="85%" color="{clrBlueLight}" text="{rectitle}" />
+ <drawtext x="{width(title)}+10" valign="center" width="{areawidth}-{width(title)}-10" font="{light}" fontsize="85%" color="{clrWhite}" text="{recsubtitle}" />
+ </area>
+ </rectitle>
+
+ <!-- Available Variables recinfo:
+ {screenwidth} width of currently displayed recording in px
+ {screenheight} height of currently displayed recording in px
+ {resolution} resolution: hd1080i, hd720p, sd576i
+ {aspect} screen aspect, each 4:3, 16:9 or 21:9
+ {isHD} true for hd1080i and hd720p
+ {isWideScreen} true if aspect is 16:9 or 21:9
+ -->
+ <recinfo>
+ <area x="70%" y="80%" width="29%" height="8%" layer="2">
+ <!-- widescreen icon -->
+ <drawimage name="widescreen" condition="{isWideScreen}" imagetype="icon" path="ico_widescreen_on" x="{areawidth} - {width(widescreen)}" valign="center" width="{areaheight}*0.8*1.87" height="{areaheight}*0.8"/>
+ <drawimage condition="not{isWideScreen}" imagetype="icon" path="ico_widescreen_off" x="{areawidth} - {width(widescreen)}" valign="center" width="{areaheight}*0.8*1.87" height="{areaheight}*0.8"/>
+ <!-- hd/sd icon -->
+ <drawimage name="hd" condition="{isHD}" imagetype="icon" path="ico_hd_on" x="{posx(widescreen)} - 15 - {width(hd)}" valign="center" width="{areaheight}*0.8*2.04" height="{areaheight}*0.8"/>
+ <drawimage condition="not{isHD}" imagetype="icon" path="ico_hd_off" x="{posx(widescreen)} - 15 - {width(hd)}" valign="center" width="{areaheight}*0.8*2.04" height="{areaheight}*0.8"/>
+ <!-- screenresolution text -->
+ <drawtext name="reslabel" x="{posx(hd)} - 30 - {width(reslabel)}" valign="center" font="{light}" fontsize="60%" color="{clrWhite}" text="{screenwidth}x{screenheight}" />
+ </area>
+ </recinfo>
+
+ <!-- Available Variables currenttime:
+ {reccurrent} Current Time in hh:mm:ss
+ -->
+ <currenttime>
+ <area x="1%" y="92%" width="30%" height="7%" layer="2">
+ <drawtext x="0" valign="center" font="{light}" fontsize="100%" color="{clrTransBlueLight}" text="{reccurrent}" />
+ </area>
+ </currenttime>
+
+ <!-- Available Variables totaltime:
+ {rectotal} Total Time in hh:mm:ss
+ -->
+ <totaltime>
+ <area x="69%" y="92%" width="30%" height="7%" layer="2">
+ <drawtext align="right" valign="center" font="{light}" fontsize="100%" color="{clrWhite}" text="{rectotal}" />
+ </area>
+ </totaltime>
+
+ <!-- Available Variables progressbar:
+ {current} current frame of recording
+ {total} total frames of recording
+ -->
+ <progressbar>
+ <area x="5%" y="89%" width="90%" height="3%" layer="2">
+ <fill color="{clrDarkGray}" />
+ <drawrectangle x="0" y="0" width="{current}/{total}*{areawidth}" height="100%" color="{clrTransBlueLight}" />
+ </area>
+ </progressbar>
+
+ <!-- Available Variables cutmarks:
+ {marks[]} array of available marks
+ {marks[position]} frame of current mark
+ {marks[endposition]} frame where startmark ends
+ {marks[total]} total number of frames
+ {marks[startmark]} true if mark is start mark
+ -->
+ <cutmarks>
+ <area x="5%" y="89%" width="90%" height="3%" layer="3">
+ <loop name="marks" x="0" y="0" orientation="absolute">
+ <drawrectangle x="{marks[position]}/{marks[total]}*{areawidth}" y="0" width="1" height="100%" color="{clrWhite}" />
+ <drawrectangle condition="{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth}" y="0" width="5" height="1" color="{clrWhite}" />
+ <drawrectangle condition="{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth}" y="{areaheight}-1" width="5" height="1" color="{clrWhite}" />
+ <drawrectangle condition="not{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth} - 5" y="0" width="5" height="1" color="{clrWhite}" />
+ <drawrectangle condition="not{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth} - 5" y="{areaheight}-1" width="5" height="1" color="{clrWhite}" />
+ <drawrectangle condition="{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth}" y="30%" width="{marks[endposition]}/{marks[total]}*{areawidth} - {marks[position]}/{marks[total]}*{areawidth}" height="40%" color="{clrWhite}" />
+ </loop>
+ </area>
+ </cutmarks>
+
+ <!-- Available Variables controlicons and controliconsmodeonly:
+ {play} true if recording is played currently
+ {pause} true if recording is paused
+ {forward} true if fast forwarding
+ {forward1x} true if fast forwarding 1x (with 3 trickspeeds)
+ {forward2x} true if fast forwarding 2x (with 3 trickspeeds)
+ {forward3x} true if fast forwarding 3x (with 3 trickspeeds)
+ {rewind} true if rewinding
+ {rewind1x} true if rewinding 1x (with 3 trickspeeds)
+ {rewind2x} true if rewinding 2x (with 3 trickspeeds)
+ {rewind3x} true if rewinding 3x (with 3 trickspeeds)
+ -->
+ <controlicons>
+ <area x="30%" y="93%" width="40%" height="7%" layer="3">
+ <drawimage condition="not{rewind} ++ not{rewind1x} ++ not{rewind2x} ++ not{rewind3x}" imagetype="icon" path="ico_rew_off" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind}" imagetype="icon" path="ico_rew" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind1x}" imagetype="icon" path="ico_rew_1x" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind2x}" imagetype="icon" path="ico_rew_2x" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind3x}" imagetype="icon" path="ico_rew_3x" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+
+ <drawimage condition="not{pause}" imagetype="icon" path="ico_pause_off" x="{areawidth}/2 - {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{pause}" imagetype="icon" path="ico_pause" x="{areawidth}/2 - {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+
+ <drawimage condition="not{play}" imagetype="icon" path="ico_play_off" x="{areawidth}/2" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{play}" imagetype="icon" path="ico_play" x="{areawidth}/2" y="0" width="{areaheight}" height="{areaheight}"/>
+
+ <drawimage condition="not{forward} ++ not{forward1x} ++ not{forward2x} ++ not{forward3x}" imagetype="icon" path="ico_ff_off" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward}" imagetype="icon" path="ico_ff" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward1x}" imagetype="icon" path="ico_ff_1x" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward2x}" imagetype="icon" path="ico_ff_2x" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward3x}" imagetype="icon" path="ico_ff_3x" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ </area>
+ </controlicons>
+
+ <controliconsmodeonly>
+ <area x="25%" y="85%" width="50%" height="10%" layer="3">
+ <drawimage condition="not{rewind} ++ not{rewind1x} ++ not{rewind2x} ++ not{rewind3x}" imagetype="icon" path="ico_rew_off" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind}" imagetype="icon" path="ico_rew" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind1x}" imagetype="icon" path="ico_rew_1x" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind2x}" imagetype="icon" path="ico_rew_2x" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind3x}" imagetype="icon" path="ico_rew_3x" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+
+ <drawimage condition="not{pause}" imagetype="icon" path="ico_pause_off" x="{areawidth}/2 - {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{pause}" imagetype="icon" path="ico_pause" x="{areawidth}/2 - {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+
+ <drawimage condition="not{play}" imagetype="icon" path="ico_play_off" x="{areawidth}/2" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{play}" imagetype="icon" path="ico_play" x="{areawidth}/2" y="0" width="{areaheight}" height="{areaheight}"/>
+
+ <drawimage condition="not{forward} ++ not{forward1x} ++ not{forward2x} ++ not{forward3x}" imagetype="icon" path="ico_ff_off" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward}" imagetype="icon" path="ico_ff" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward1x}" imagetype="icon" path="ico_ff_1x" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward2x}" imagetype="icon" path="ico_ff_2x" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward3x}" imagetype="icon" path="ico_ff_3x" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ </area>
+ </controliconsmodeonly>
+
+ <!-- Available Variables jump:
+ {jump} time to jump to in hh:mm
+ -->
+ <jump>
+ <area x="35%" y="45%" width="30%" height="10%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <area x="35%" y="45%" width="30%" height="10%" layer="2">
+ <drawtext align="center" valign="center" font="{light}" fontsize="80%" color="{clrWhite}" text="{jump}" />
+ </area>
+ </jump>
+ <!-- Available Variables message:
+ {text} message text
+ {status} true if message is a status message
+ {info} true if message is a info message
+ {warning} true if message is a warn message
+ {error} true if message is a error message
+ -->
+ <message>
+ <area x="10%" y="45%" width="80%" height="10%" layer="1">
+ <drawrectangle condition="{status}" x="20" y="0" width="20" height="100%" color="{clrGreen}" />
+ <drawrectangle condition="{info}" x="20" y="0" width="20" height="100%" color="{clrBlue}" />
+ <drawrectangle condition="{warning}" x="20" y="0" width="20" height="100%" color="{clrYellow}" />
+ <drawrectangle condition="{error}" x="20" y="0" width="20" height="100%" color="{clrRed}" />
+ <drawtext align="center" valign="center" width="{areawidth} - 80" font="{light}" fontsize="40%" color="{clrWhite}" text="{text}" />
+ </area>
+ </message>
+</displayreplay>
diff --git a/skins/default/xmlfiles/displayvolume.xml b/skins/default/xmlfiles/displayvolume.xml
new file mode 100644
index 0000000..25a54fe
--- /dev/null
+++ b/skins/default/xmlfiles/displayvolume.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displayvolume SYSTEM "../../dtd/displayvolume.dtd">
+
+<displayvolume x="20%" y="75%" width="60%" height="20%" fadetime="{fadeTime}">
+ <background>
+ <area x="0" y="0" width="100%" height="100%" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ </background>
+
+ <!-- Available Variables volume:
+ {volume} current volume, range from 0 to 255
+ {volumepercent} current volume in %
+ {maxvolume} maximal volume
+ {mute} true if volume is muted
+ -->
+ <volume>
+ <area x="0" y="0" width="100%" height="50%" layer="2">
+ <drawtext x="10" valign="center" font="{light}" fontsize="100%" color="{clrWhite}" text="{tr(volume)}: {volumepercent}%" />
+ <drawimage condition="not{mute}" imagetype="icon" path="ico_volume" x="{areawidth} - {areaheight} - 5" y="5" width="{areaheight}-5" height="{areaheight}-5"/>
+ <drawimage condition="{mute}" imagetype="icon" path="ico_mute" x="{areawidth} - {areaheight} - 5" y="5" width="{areaheight}-5" height="{areaheight}-5"/>
+ </area>
+ <area x="5%" y="60%" width="90%" height="30%" layer="2">
+ <fill color="{clrDarkGray}" />
+ <drawrectangle x="0" y="0" width="{volume}/{maxvolume}*{areawidth}" height="100%" color="{clrTransBlueLight}" />
+ </area>
+ </volume>
+
+</displayvolume>
diff --git a/skins/default/xmlfiles/globals.xml b/skins/default/xmlfiles/globals.xml
new file mode 100644
index 0000000..b66ddcb
--- /dev/null
+++ b/skins/default/xmlfiles/globals.xml
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE globals SYSTEM "../../dtd/globals.dtd">
+
+<globals>
+ <!--
+ define all your needed colors here
+ -->
+ <colors>
+ <color name="clrRed">FFFF0000</color>
+ <color name="clrGreen">FF5FE200</color>
+ <color name="clrYellow">FFE2DA00</color>
+ <color name="clrBlue">FF007FE2</color>
+ <color name="clrTransBlack">C0000000</color>
+ <color name="clrSemiTransBlack">D0000000</color>
+ <color name="clrBlueLight">FF1E8BD7</color>
+ <color name="clrTransBlueLight">C01E8BD7</color>
+ <color name="clrTransWhite">C0FFFFFF</color>
+ <color name="clrWhite">FFFFFFFF</color>
+ <color name="clrDarkGray">FF14141E</color>
+ <color name="clrTransparent">00000000</color>
+ </colors>
+ <!--
+ these variables can be used everywhere in the templates
+ variabls of type int can also be used as conditions, just
+ set such a variable to 1 for true and 0 for false
+ -->
+ <variables>
+ <var type="int" name="border">5</var>
+ <var type="int" name="fadeTime">0</var>
+ <var type="string" name="stringglobal">hützligrütz</var>
+ </variables>
+ <!--
+ translations used in the skin
+ -->
+ <translations>
+ <token name="tr(activetimers)">
+ <trans lang="en_EN">Active Timers</trans>
+ <trans lang="de_DE">Aktive Timer</trans>
+ </token>
+ <token name="tr(activetimer)">
+ <trans lang="en_EN">Active Timer</trans>
+ <trans lang="de_DE">Aktiver Timer</trans>
+ </token>
+ <token name="tr(conflicts)">
+ <trans lang="en_EN">Conflicts</trans>
+ <trans lang="de_DE">Konflikte</trans>
+ </token>
+ <token name="tr(disc)">
+ <trans lang="en_EN">Disc</trans>
+ <trans lang="de_DE">Disk</trans>
+ </token>
+ <token name="tr(free)">
+ <trans lang="en_EN">free</trans>
+ <trans lang="de_DE">frei</trans>
+ </token>
+ <token name="tr(hours)">
+ <trans lang="en_EN">hours</trans>
+ <trans lang="de_DE">Stunden</trans>
+ </token>
+ <token name="tr(reruns)">
+ <trans lang="en_EN">Reruns</trans>
+ <trans lang="de_DE">Wiederholungen</trans>
+ </token>
+ <token name="tr(rerunsof)">
+ <trans lang="en_EN">Reruns of</trans>
+ <trans lang="de_DE">Wiederholungen von</trans>
+ </token>
+ <token name="tr(actors)">
+ <trans lang="en_EN">Actors</trans>
+ <trans lang="de_DE">Schauspieler</trans>
+ </token>
+ <token name="tr(episode)">
+ <trans lang="en_EN">Episode</trans>
+ <trans lang="de_DE">Folge</trans>
+ </token>
+ <token name="tr(season)">
+ <trans lang="en_EN">Season</trans>
+ <trans lang="de_DE">Staffel</trans>
+ </token>
+ <token name="tr(gueststars)">
+ <trans lang="en_EN">Guest Stars</trans>
+ <trans lang="de_DE">Gaststars</trans>
+ </token>
+ <token name="tr(seriesfirstaired)">
+ <trans lang="en_EN">Series First Aired</trans>
+ <trans lang="de_DE">Erstausstrahlung der Serie</trans>
+ </token>
+ <token name="tr(episodefirstaired)">
+ <trans lang="en_EN">Episode First Aired</trans>
+ <trans lang="de_DE">Erstausstrahlung der Episode</trans>
+ </token>
+ <token name="tr(network)">
+ <trans lang="en_EN">Network</trans>
+ <trans lang="de_DE">TV Station</trans>
+ </token>
+ <token name="tr(genre)">
+ <trans lang="en_EN">Genre</trans>
+ <trans lang="de_DE">Genre</trans>
+ </token>
+ <token name="tr(status)">
+ <trans lang="en_EN">Status</trans>
+ <trans lang="de_DE">Status</trans>
+ </token>
+ <token name="tr(rating)">
+ <trans lang="en_EN">Rating</trans>
+ <trans lang="de_DE">Bewertung</trans>
+ </token>
+ <token name="tr(episoderating)">
+ <trans lang="en_EN">Episode Rating</trans>
+ <trans lang="de_DE">Bewertung der Folge</trans>
+ </token>
+ <token name="tr(recinfo)">
+ <trans lang="en_EN">Recording Information</trans>
+ <trans lang="de_DE">Aufnahme Informationen</trans>
+ </token>
+ <token name="tr(seriesgalery)">
+ <trans lang="en_EN">Series Galery</trans>
+ <trans lang="de_DE">Serien Galerie</trans>
+ </token>
+ <token name="tr(moviegalery)">
+ <trans lang="en_EN">Movie Galery</trans>
+ <trans lang="de_DE">Spielfilm Galerie</trans>
+ </token>
+ <token name="tr(originaltitle)">
+ <trans lang="en_EN">Original Title</trans>
+ <trans lang="de_DE">Originaltitel</trans>
+ </token>
+ <token name="tr(budget)">
+ <trans lang="en_EN">Budget</trans>
+ <trans lang="de_DE">Budget</trans>
+ </token>
+ <token name="tr(revenue)">
+ <trans lang="en_EN">Revenue</trans>
+ <trans lang="de_DE">Einnahmen</trans>
+ </token>
+ <token name="tr(adult)">
+ <trans lang="en_EN">Adult</trans>
+ <trans lang="de_DE">Nur für Erwachsene</trans>
+ </token>
+ <token name="tr(releasedate)">
+ <trans lang="en_EN">Release Date</trans>
+ <trans lang="de_DE">Erscheinungsdatum</trans>
+ </token>
+ <token name="tr(runtime)">
+ <trans lang="en_EN">Runtime</trans>
+ <trans lang="de_DE">Laufzeit</trans>
+ </token>
+ <token name="tr(popularity)">
+ <trans lang="en_EN">Popularity</trans>
+ <trans lang="de_DE">Popularität</trans>
+ </token>
+ <token name="tr(voteaverage)">
+ <trans lang="en_EN">Vote Average</trans>
+ <trans lang="de_DE">Durchschnittliche Wertung</trans>
+ </token>
+ <token name="tr(homepage)">
+ <trans lang="en_EN">Homepage</trans>
+ <trans lang="de_DE">Homepage</trans>
+ </token>
+ <token name="tr(recsize)">
+ <trans lang="en_EN">Recording size</trans>
+ <trans lang="de_DE">Größe der Aufnahme</trans>
+ </token>
+ <token name="tr(recsizecutted)">
+ <trans lang="en_EN">Cutted Recording Size</trans>
+ <trans lang="de_DE">Größe der geschnittenen Aufnahme</trans>
+ </token>
+ <token name="tr(reclength)">
+ <trans lang="en_EN">Recording Length</trans>
+ <trans lang="de_DE">Länge der Aufnahme</trans>
+ </token>
+ <token name="tr(reclengthcutted)">
+ <trans lang="en_EN">Cutted Recording Length</trans>
+ <trans lang="de_DE">Länge der geschnittenen Aufnahme</trans>
+ </token>
+ <token name="tr(bitrate)">
+ <trans lang="en_EN">Bit Rate</trans>
+ <trans lang="de_DE">Bitrate</trans>
+ </token>
+ <token name="tr(format)">
+ <trans lang="en_EN">Format</trans>
+ <trans lang="de_DE">Format</trans>
+ </token>
+ <token name="tr(searchtimer)">
+ <trans lang="en_EN">Searchtimer</trans>
+ <trans lang="de_DE">Suchtimer</trans>
+ </token>
+ <token name="tr(volume)">
+ <trans lang="en_EN">Volume</trans>
+ <trans lang="de_DE">Lautstärke</trans>
+ </token>
+ </translations>
+ <!--
+ The three Fonts FontOSD, FontFix and FontSml configured in VDR
+ can be used in all template "font" attributes with this tokens:
+ {vdrOsd}
+ {vdrFix}
+ {vdrSml}
+ If you like to use further fonts, just define them below.
+ Syntax:
+ <font name="tokenname">fontname</font>
+ These fonts can then also be used in all templates in the "font"
+ attribute.
+ if an invalid font is used in a template, vdrOsd is used as default.
+ -->
+ <fonts>
+ <font name="light">VDROpen Sans Light:Light</font>
+ <font name="semibold">VDROpen Sans Semibold:Semibold</font>
+ </fonts>
+</globals>
diff --git a/skins/dtd/displayaudiotracks.dtd b/skins/dtd/displayaudiotracks.dtd
new file mode 100644
index 0000000..e6cd869
--- /dev/null
+++ b/skins/dtd/displayaudiotracks.dtd
@@ -0,0 +1,42 @@
+<?xml encoding="UTF-8"?>
+
+<!ENTITY % functions SYSTEM "functions.dtd">
+
+<!ELEMENT displayaudiotracks (background | header | menuitems)*>
+<!ATTLIST displayaudiotracks
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT background (area|areascroll)*>
+<!ATTLIST background
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT header (area|areascroll)*>
+<!ATTLIST header
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT menuitems (listelement)>
+<!ATTLIST menuitems
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ align (left|top|center|bottom|right) #IMPLIED
+ menuitemwidth CDATA #IMPLIED
+ numlistelements CDATA #REQUIRED
+ orientation (horizontal|vertical) #REQUIRED
+>
+
+<!ELEMENT listelement (area|areascroll)*>
+
+%functions; \ No newline at end of file
diff --git a/skins/dtd/displaychannel.dtd b/skins/dtd/displaychannel.dtd
new file mode 100644
index 0000000..538540b
--- /dev/null
+++ b/skins/dtd/displaychannel.dtd
@@ -0,0 +1,86 @@
+<?xml encoding="UTF-8"?>
+
+<!ENTITY % functions SYSTEM "functions.dtd">
+
+<!ELEMENT displaychannel (background | channelinfo | epginfo | progressbar | progressbarback |
+ statusinfo | screenresolution | channelgroup |
+ signalquality | signalqualityback | scrapercontent |
+ datetime | message)* >
+<!ATTLIST displaychannel
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT background (area)*>
+<!ATTLIST background
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT channelinfo (area|areascroll)*>
+<!ATTLIST channelinfo
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT epginfo (area|areascroll)*>
+<!ATTLIST epginfo
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT progressbar (area|areascroll)*>
+<!ATTLIST progressbar
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT progressbarback (area)*>
+<!ATTLIST progressbarback
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT statusinfo (area|areascroll)*>
+<!ATTLIST statusinfo
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT screenresolution (area|areascroll)*>
+<!ATTLIST screenresolution
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT channelgroup (area|areascroll)*>
+<!ATTLIST channelgroup
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT signalquality (area|areascroll)*>
+<!ATTLIST signalquality
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT signalqualityback (area|areascroll)*>
+<!ATTLIST signalqualityback
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT scrapercontent (area|areascroll)*>
+<!ATTLIST scrapercontent
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT datetime (area|areascroll)*>
+<!ATTLIST datetime
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT message (area|areascroll)*>
+<!ATTLIST message
+ debug CDATA #IMPLIED
+>
+
+%functions;
diff --git a/skins/dtd/displaymenu.dtd b/skins/dtd/displaymenu.dtd
new file mode 100644
index 0000000..b70a944
--- /dev/null
+++ b/skins/dtd/displaymenu.dtd
@@ -0,0 +1,251 @@
+<?xml encoding="UTF-8"?>
+
+<!ENTITY % functions SYSTEM "functions.dtd">
+
+<!ELEMENT displaymenu (background,header,datetime,message,colorbuttons,
+ menudefault,menumain,menusetup,menuschedules,
+ menutimers,menuchannels,menurecordings,
+ menudetailedepg,menudetailedrecording,
+ menudetailedtext)>
+<!ATTLIST displaymenu
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+>
+
+<!ELEMENT background (area)*>
+<!ATTLIST background
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT header (area|areascroll)*>
+<!ATTLIST header
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT datetime (area|areascroll)*>
+<!ATTLIST datetime
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT message (area|areascroll)*>
+<!ATTLIST message
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT colorbuttons (area|areascroll)*>
+<!ATTLIST colorbuttons
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT timers (area|areascroll)*>
+<!ATTLIST timers
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT discusage (area|areascroll)*>
+<!ATTLIST discusage
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT devices (area|areascroll)*>
+<!ATTLIST devices
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT systemload (area|areascroll)*>
+<!ATTLIST systemload
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT scrollbar (area|areascroll)*>
+<!ATTLIST scrollbar
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT detailheader (area|areascroll)*>
+<!ATTLIST detailheader
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT tablabels (area|areascroll)*>
+<!ATTLIST tablabels
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT menudefault (background | header | datetime | colorbuttons | scrollbar | menuitems)*>
+<!ATTLIST menudefault
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT menumain (background | header | datetime | colorbuttons | scrollbar | timers |
+ discusage | devices | systemload | menuitems)*>
+<!ATTLIST menumain
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT menusetup (background | header | datetime | colorbuttons | scrollbar | menuitems)*>
+<!ATTLIST menusetup
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT menuschedules (background | header | datetime | colorbuttons | scrollbar | menuitems)*>
+<!ATTLIST menuschedules
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT menutimers (background | header | datetime | colorbuttons | scrollbar | menuitems)*>
+<!ATTLIST menutimers
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT menuchannels (background | header | datetime | colorbuttons | scrollbar | menuitems)*>
+<!ATTLIST menuchannels
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT menurecordings (background | header | datetime | colorbuttons | scrollbar | menuitems)*>
+<!ATTLIST menurecordings
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT menudetailedepg (background | header | datetime | colorbuttons | scrollbar |
+ detailheader | tab | tablabels)*>
+<!ATTLIST menudetailedepg
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT menudetailedrecording (background | header | datetime | colorbuttons | scrollbar |
+ detailheader | tab | tablabels)*>
+<!ATTLIST menudetailedrecording
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT menudetailedtext (background | header | datetime | colorbuttons | scrollbar |
+ detailheader | tab )*>
+<!ATTLIST menudetailedtext
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT menuitems (listelement,currentelement?)>
+<!ATTLIST menuitems
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ align (left|top|center|bottom|right) #IMPLIED
+ menuitemwidth CDATA #IMPLIED
+ determinatefont CDATA #IMPLIED
+ numlistelements CDATA #REQUIRED
+ orientation (horizontal|vertical) #REQUIRED
+>
+
+<!ELEMENT listelement (area|areascroll)*>
+<!ATTLIST listelement
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT currentelement (area|areascroll)*>
+<!ATTLIST currentelement
+ delay CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT tab (loop|fill|drawtext|drawtextbox|drawimage|drawrectangle|drawellipse)*>
+<!ATTLIST tab
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ layer CDATA #REQUIRED
+ name CDATA #REQUIRED
+ scrollheight CDATA #REQUIRED
+ transparency CDATA #IMPLIED
+ condition CDATA #IMPLIED
+ debug (true|false) #IMPLIED
+>
+
+%functions; \ No newline at end of file
diff --git a/skins/dtd/displaymessage.dtd b/skins/dtd/displaymessage.dtd
new file mode 100644
index 0000000..223ea2d
--- /dev/null
+++ b/skins/dtd/displaymessage.dtd
@@ -0,0 +1,28 @@
+<?xml encoding="UTF-8"?>
+
+<!ENTITY % functions SYSTEM "functions.dtd">
+
+<!ELEMENT displaymessage (background | message)*>
+<!ATTLIST displaymessage
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT background (area)*>
+<!ATTLIST background
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT message (area|areascroll)*>
+<!ATTLIST message
+ debug CDATA #IMPLIED
+>
+
+%functions; \ No newline at end of file
diff --git a/skins/dtd/displayreplay.dtd b/skins/dtd/displayreplay.dtd
new file mode 100644
index 0000000..baf06d2
--- /dev/null
+++ b/skins/dtd/displayreplay.dtd
@@ -0,0 +1,91 @@
+<?xml encoding="UTF-8"?>
+
+<!ENTITY % functions SYSTEM "functions.dtd">
+
+<!ELEMENT displayreplay (background | backgroundmodeonly |datetime |
+ scrapercontent | rectitle | recinfo | currenttime |
+ totaltime | progressbar | cutmarks | controlicons |
+ controliconsmodeonly | jump | message)*>
+<!ATTLIST displayreplay
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT background (area)*>
+<!ATTLIST background
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT backgroundmodeonly (area)*>
+<!ATTLIST backgroundmodeonly
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT datetime (area|areascroll)*>
+<!ATTLIST datetime
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT scrapercontent (area|areascroll)*>
+<!ATTLIST scrapercontent
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT rectitle (area|areascroll)*>
+<!ATTLIST rectitle
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT recinfo (area|areascroll)*>
+<!ATTLIST recinfo
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT currenttime (area|areascroll)*>
+<!ATTLIST currenttime
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT totaltime (area|areascroll)*>
+<!ATTLIST totaltime
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT progressbar (area|areascroll)*>
+<!ATTLIST progressbar
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT cutmarks (area|areascroll)*>
+<!ATTLIST cutmarks
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT controlicons (area|areascroll)*>
+<!ATTLIST controlicons
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT controliconsmodeonly (area|areascroll)*>
+<!ATTLIST controliconsmodeonly
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT jump (area|areascroll)*>
+<!ATTLIST jump
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT message (area|areascroll)*>
+<!ATTLIST message
+ debug CDATA #IMPLIED
+>
+
+%functions; \ No newline at end of file
diff --git a/skins/dtd/displayvolume.dtd b/skins/dtd/displayvolume.dtd
new file mode 100644
index 0000000..2be597d
--- /dev/null
+++ b/skins/dtd/displayvolume.dtd
@@ -0,0 +1,28 @@
+<?xml encoding="UTF-8"?>
+
+<!ENTITY % functions SYSTEM "functions.dtd">
+
+<!ELEMENT displayvolume (background | volume)*>
+<!ATTLIST displayvolume
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #REQUIRED
+ fadetime CDATA #IMPLIED
+ scaletvx CDATA #IMPLIED
+ scaletvy CDATA #IMPLIED
+ scaletvwidth CDATA #IMPLIED
+ scaletvheight CDATA #IMPLIED
+>
+
+<!ELEMENT background (area)*>
+<!ATTLIST background
+ debug CDATA #IMPLIED
+>
+
+<!ELEMENT volume (area|areascroll)*>
+<!ATTLIST volume
+ debug CDATA #IMPLIED
+>
+
+%functions;
diff --git a/skins/dtd/functions.dtd b/skins/dtd/functions.dtd
new file mode 100644
index 0000000..5e78876
--- /dev/null
+++ b/skins/dtd/functions.dtd
@@ -0,0 +1,131 @@
+<!ELEMENT area (loop|fill|drawtext|drawtextbox|drawimage|drawrectangle|drawellipse)*>
+<!ATTLIST area
+ x CDATA #IMPLIED
+ y CDATA #IMPLIED
+ width CDATA #IMPLIED
+ height CDATA #IMPLIED
+ layer CDATA #REQUIRED
+ transparency CDATA #IMPLIED
+ condition CDATA #IMPLIED
+ debug (true|false) #IMPLIED
+>
+
+<!ELEMENT areascroll (loop|fill|drawtext|drawtextbox|drawimage|drawrectangle|drawellipse)*>
+<!ATTLIST areascroll
+ x CDATA #IMPLIED
+ y CDATA #IMPLIED
+ width CDATA #IMPLIED
+ height CDATA #IMPLIED
+ layer CDATA #REQUIRED
+ transparency CDATA #IMPLIED
+ mode (forthandback|carriagereturn) #REQUIRED
+ orientation (horizontal|vertical) #REQUIRED
+ scrollelement CDATA #IMPLIED
+ scrollspeed (slow|medium|fast) #REQUIRED
+ condition CDATA #IMPLIED
+ delay CDATA #REQUIRED
+ debug (true|false) #IMPLIED
+>
+
+<!ELEMENT loop (drawtext|drawtextbox|drawimage|drawrectangle|drawellipse)+>
+<!ATTLIST loop
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #IMPLIED
+ height CDATA #IMPLIED
+ columnwidth CDATA #IMPLIED
+ rowheight CDATA #IMPLIED
+ name CDATA #REQUIRED
+ orientation (horizontal|vertical|absolute) #REQUIRED
+ overflow (linewrap|cut) #IMPLIED
+ maxitems CDATA #IMPLIED
+ debug (true|false) #IMPLIED
+>
+
+<!ELEMENT fill EMPTY>
+<!ATTLIST fill
+ color CDATA #REQUIRED
+ condition CDATA #IMPLIED
+ debug (true|false) #IMPLIED
+>
+
+<!ELEMENT drawtext EMPTY>
+<!ATTLIST drawtext
+ x CDATA #IMPLIED
+ y CDATA #IMPLIED
+ width CDATA #IMPLIED
+ align (left|center|right) #IMPLIED
+ valign (top|center|bottom) #IMPLIED
+ color CDATA #REQUIRED
+ font CDATA #REQUIRED
+ fontsize CDATA #REQUIRED
+ name NMTOKEN #IMPLIED
+ text CDATA #REQUIRED
+ condition CDATA #IMPLIED
+ debug (true|false) #IMPLIED
+>
+
+<!ELEMENT drawtextbox EMPTY>
+<!ATTLIST drawtextbox
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #REQUIRED
+ height CDATA #IMPLIED
+ align (left|center|right) #IMPLIED
+ maxlines CDATA #IMPLIED
+ floatwidth CDATA #IMPLIED
+ floatheight CDATA #IMPLIED
+ float (topleft|topright) #IMPLIED
+ color CDATA #REQUIRED
+ font CDATA #REQUIRED
+ fontsize CDATA #REQUIRED
+ name NMTOKEN #IMPLIED
+ text CDATA #REQUIRED
+ condition CDATA #IMPLIED
+ debug NMTOKEN #IMPLIED
+>
+
+<!ELEMENT drawrectangle EMPTY>
+<!ATTLIST drawrectangle
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #IMPLIED
+ height CDATA #IMPLIED
+ align (left|center|right) #IMPLIED
+ valign (top|center|bottom) #IMPLIED
+ color CDATA #REQUIRED
+ name NMTOKEN #IMPLIED
+ condition CDATA #IMPLIED
+ debug NMTOKEN #IMPLIED
+ >
+
+<!ELEMENT drawellipse EMPTY>
+<!ATTLIST drawellipse
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ width CDATA #IMPLIED
+ height CDATA #IMPLIED
+ align (left|center|right) #IMPLIED
+ valign (top|center|bottom) #IMPLIED
+ color CDATA #REQUIRED
+ quadrant CDATA #REQUIRED
+ name NMTOKEN #IMPLIED
+ condition CDATA #IMPLIED
+ debug NMTOKEN #IMPLIED
+ >
+
+<!ELEMENT drawimage EMPTY>
+<!ATTLIST drawimage
+ x CDATA #IMPLIED
+ y CDATA #IMPLIED
+ width CDATA #IMPLIED
+ height CDATA #IMPLIED
+ align (left|center|right) #IMPLIED
+ valign (top|center|bottom) #IMPLIED
+ imagetype (channellogo|seplogo|skinpart|menuicon|icon|image) #REQUIRED
+ cache (true|false) #IMPLIED
+ path CDATA #REQUIRED
+ name CDATA #IMPLIED
+ condition CDATA #IMPLIED
+ debug NMTOKEN #IMPLIED
+>
diff --git a/skins/dtd/globals.dtd b/skins/dtd/globals.dtd
new file mode 100644
index 0000000..570fa15
--- /dev/null
+++ b/skins/dtd/globals.dtd
@@ -0,0 +1,29 @@
+<?xml encoding="UTF-8"?>
+
+<!ELEMENT globals (colors,variables,translations,fonts)>
+<!ELEMENT colors (color)*>
+<!ELEMENT variables (var)*>
+<!ELEMENT translations (token)*>
+<!ELEMENT fonts (font)*>
+
+<!ELEMENT color (#PCDATA)>
+<!ATTLIST color
+ name NMTOKEN #REQUIRED>
+
+<!ELEMENT var (#PCDATA)>
+<!ATTLIST var
+ name NMTOKEN #REQUIRED
+ type (int|string) #REQUIRED>
+
+<!ELEMENT token (trans)+>
+<!ATTLIST token
+ name CDATA #REQUIRED>
+
+<!ELEMENT trans (#PCDATA)>
+<!ATTLIST trans
+ lang NMTOKEN #REQUIRED>
+
+<!ELEMENT font (#PCDATA)>
+<!ATTLIST font
+ name NMTOKEN #REQUIRED>
+
diff --git a/skins/nopacity/graphics/icons/ico_ac3.png b/skins/nopacity/graphics/icons/ico_ac3.png
new file mode 100644
index 0000000..5b8614a
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_ac3.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_activetimer.png b/skins/nopacity/graphics/icons/ico_activetimer.png
new file mode 100644
index 0000000..af4c33c
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_activetimer.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_arrow_left_channelsep.png b/skins/nopacity/graphics/icons/ico_arrow_left_channelsep.png
new file mode 100644
index 0000000..642cd78
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_arrow_left_channelsep.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_arrow_right_channelsep.png b/skins/nopacity/graphics/icons/ico_arrow_right_channelsep.png
new file mode 100644
index 0000000..1418671
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_arrow_right_channelsep.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_channelsep.png b/skins/nopacity/graphics/icons/ico_channelsep.png
new file mode 100644
index 0000000..bf51238
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_channelsep.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_cutted.png b/skins/nopacity/graphics/icons/ico_cutted.png
new file mode 100644
index 0000000..b90c9c1
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_cutted.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_daydelimiter.png b/skins/nopacity/graphics/icons/ico_daydelimiter.png
new file mode 100644
index 0000000..7ae6053
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_daydelimiter.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_discusage.png b/skins/nopacity/graphics/icons/ico_discusage.png
new file mode 100644
index 0000000..f40fcd9
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_discusage.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_dolbyoff.png b/skins/nopacity/graphics/icons/ico_dolbyoff.png
new file mode 100644
index 0000000..ef4f17c
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_dolbyoff.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_dolbyon.png b/skins/nopacity/graphics/icons/ico_dolbyon.png
new file mode 100644
index 0000000..1278abe
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_dolbyon.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_encrypted.png b/skins/nopacity/graphics/icons/ico_encrypted.png
new file mode 100644
index 0000000..2b6345a
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_encrypted.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_ff.png b/skins/nopacity/graphics/icons/ico_ff.png
new file mode 100644
index 0000000..3dea9d3
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_ff.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_ff_1x.png b/skins/nopacity/graphics/icons/ico_ff_1x.png
new file mode 100644
index 0000000..599256e
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_ff_1x.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_ff_2x.png b/skins/nopacity/graphics/icons/ico_ff_2x.png
new file mode 100644
index 0000000..3eec356
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_ff_2x.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_ff_3x.png b/skins/nopacity/graphics/icons/ico_ff_3x.png
new file mode 100644
index 0000000..f686658
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_ff_3x.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_ff_off.png b/skins/nopacity/graphics/icons/ico_ff_off.png
new file mode 100644
index 0000000..cb551c2
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_ff_off.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_fta.png b/skins/nopacity/graphics/icons/ico_fta.png
new file mode 100644
index 0000000..55e3789
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_fta.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_hd1080i.png b/skins/nopacity/graphics/icons/ico_hd1080i.png
new file mode 100644
index 0000000..27b85ab
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_hd1080i.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_hd720p.png b/skins/nopacity/graphics/icons/ico_hd720p.png
new file mode 100644
index 0000000..47317d8
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_hd720p.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_mute.png b/skins/nopacity/graphics/icons/ico_mute.png
new file mode 100644
index 0000000..4eefc75
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_mute.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_pause.png b/skins/nopacity/graphics/icons/ico_pause.png
new file mode 100644
index 0000000..cd8cad8
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_pause.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_pause_off.png b/skins/nopacity/graphics/icons/ico_pause_off.png
new file mode 100644
index 0000000..f9a9d94
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_pause_off.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_play.png b/skins/nopacity/graphics/icons/ico_play.png
new file mode 100644
index 0000000..4cc0541
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_play.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_play_off.png b/skins/nopacity/graphics/icons/ico_play_off.png
new file mode 100644
index 0000000..7fb820a
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_play_off.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_recfolder.png b/skins/nopacity/graphics/icons/ico_recfolder.png
new file mode 100644
index 0000000..e3df65b
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_recfolder.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_recnew.png b/skins/nopacity/graphics/icons/ico_recnew.png
new file mode 100644
index 0000000..b9166ba
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_recnew.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_recoff.png b/skins/nopacity/graphics/icons/ico_recoff.png
new file mode 100644
index 0000000..4f59218
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_recoff.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_recon.png b/skins/nopacity/graphics/icons/ico_recon.png
new file mode 100644
index 0000000..14fe7be
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_recon.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_rew.png b/skins/nopacity/graphics/icons/ico_rew.png
new file mode 100644
index 0000000..72408d0
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_rew.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_rew_1x.png b/skins/nopacity/graphics/icons/ico_rew_1x.png
new file mode 100644
index 0000000..333c30d
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_rew_1x.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_rew_2x.png b/skins/nopacity/graphics/icons/ico_rew_2x.png
new file mode 100644
index 0000000..c5d1084
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_rew_2x.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_rew_3x.png b/skins/nopacity/graphics/icons/ico_rew_3x.png
new file mode 100644
index 0000000..6ab7a8d
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_rew_3x.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_rew_off.png b/skins/nopacity/graphics/icons/ico_rew_off.png
new file mode 100644
index 0000000..ce18386
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_rew_off.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_sd576i.png b/skins/nopacity/graphics/icons/ico_sd576i.png
new file mode 100644
index 0000000..994a7a2
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_sd576i.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_stereo.png b/skins/nopacity/graphics/icons/ico_stereo.png
new file mode 100644
index 0000000..7f3610d
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_stereo.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_stereooff.png b/skins/nopacity/graphics/icons/ico_stereooff.png
new file mode 100644
index 0000000..569a342
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_stereooff.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_stereoon.png b/skins/nopacity/graphics/icons/ico_stereoon.png
new file mode 100644
index 0000000..eb838b9
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_stereoon.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_timer_active.png b/skins/nopacity/graphics/icons/ico_timer_active.png
new file mode 100644
index 0000000..28c2f81
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_timer_active.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_timer_inactive.png b/skins/nopacity/graphics/icons/ico_timer_inactive.png
new file mode 100644
index 0000000..c4b1860
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_timer_inactive.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_timer_recording.png b/skins/nopacity/graphics/icons/ico_timer_recording.png
new file mode 100644
index 0000000..86dc66b
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_timer_recording.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_txtoff.png b/skins/nopacity/graphics/icons/ico_txtoff.png
new file mode 100644
index 0000000..3b2eac3
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_txtoff.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_txton.png b/skins/nopacity/graphics/icons/ico_txton.png
new file mode 100644
index 0000000..148f9ef
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_txton.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_vdrlogo.png b/skins/nopacity/graphics/icons/ico_vdrlogo.png
new file mode 100644
index 0000000..200cea7
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_vdrlogo.png
Binary files differ
diff --git a/skins/nopacity/graphics/icons/ico_volume.png b/skins/nopacity/graphics/icons/ico_volume.png
new file mode 100644
index 0000000..3a72514
--- /dev/null
+++ b/skins/nopacity/graphics/icons/ico_volume.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Applikationen.png b/skins/nopacity/graphics/menuicons/customicons/Applikationen.png
new file mode 100644
index 0000000..3c3b616
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Applikationen.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Audio.png b/skins/nopacity/graphics/menuicons/customicons/Audio.png
new file mode 100644
index 0000000..ff387fe
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Audio.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Aufnahmen-Liste aktualisieren.png b/skins/nopacity/graphics/menuicons/customicons/Aufnahmen-Liste aktualisieren.png
new file mode 100644
index 0000000..3cdddc9
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Aufnahmen-Liste aktualisieren.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Dienstprogramme.png b/skins/nopacity/graphics/menuicons/customicons/Dienstprogramme.png
new file mode 100644
index 0000000..793aba6
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Dienstprogramme.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/FireFox.png b/skins/nopacity/graphics/menuicons/customicons/FireFox.png
new file mode 100644
index 0000000..192fadc
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/FireFox.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Info.png b/skins/nopacity/graphics/menuicons/customicons/Info.png
new file mode 100644
index 0000000..6737431
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Info.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Internet.png b/skins/nopacity/graphics/menuicons/customicons/Internet.png
new file mode 100644
index 0000000..f3db150
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Internet.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Medien.png b/skins/nopacity/graphics/menuicons/customicons/Medien.png
new file mode 100644
index 0000000..0ce2360
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Medien.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Rechner neu starten.png b/skins/nopacity/graphics/menuicons/customicons/Rechner neu starten.png
new file mode 100644
index 0000000..5783ccf
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Rechner neu starten.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Remote wakeup.png b/skins/nopacity/graphics/menuicons/customicons/Remote wakeup.png
new file mode 100644
index 0000000..1cd2f6e
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Remote wakeup.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Spiele.png b/skins/nopacity/graphics/menuicons/customicons/Spiele.png
new file mode 100644
index 0000000..8e07161
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Spiele.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/System herunterfahren.png b/skins/nopacity/graphics/menuicons/customicons/System herunterfahren.png
new file mode 100644
index 0000000..e0234df
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/System herunterfahren.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/System.png b/skins/nopacity/graphics/menuicons/customicons/System.png
new file mode 100644
index 0000000..81d100e
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/System.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Tools.png b/skins/nopacity/graphics/menuicons/customicons/Tools.png
new file mode 100644
index 0000000..cf328ef
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Tools.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Tunderbird.png b/skins/nopacity/graphics/menuicons/customicons/Tunderbird.png
new file mode 100644
index 0000000..5ae27e0
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Tunderbird.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/USB Massenspeicher sicher entfernen.png b/skins/nopacity/graphics/menuicons/customicons/USB Massenspeicher sicher entfernen.png
new file mode 100644
index 0000000..cd7b81c
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/USB Massenspeicher sicher entfernen.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/VDR neu starten.png b/skins/nopacity/graphics/menuicons/customicons/VDR neu starten.png
new file mode 100644
index 0000000..14904ca
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/VDR neu starten.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Video.png b/skins/nopacity/graphics/menuicons/customicons/Video.png
new file mode 100644
index 0000000..490ca4b
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Video.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Web.png b/skins/nopacity/graphics/menuicons/customicons/Web.png
new file mode 100644
index 0000000..20260e3
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Web.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/XBMC.png b/skins/nopacity/graphics/menuicons/customicons/XBMC.png
new file mode 100644
index 0000000..c7c4c04
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/XBMC.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/Xterm.png b/skins/nopacity/graphics/menuicons/customicons/Xterm.png
new file mode 100644
index 0000000..fa75282
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/Xterm.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/audiovideo.png b/skins/nopacity/graphics/menuicons/customicons/audiovideo.png
new file mode 100644
index 0000000..726538d
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/audiovideo.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/markad_status.png b/skins/nopacity/graphics/menuicons/customicons/markad_status.png
new file mode 100644
index 0000000..4fdc7a4
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/markad_status.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/schneiden_abbrechen.png b/skins/nopacity/graphics/menuicons/customicons/schneiden_abbrechen.png
new file mode 100644
index 0000000..b2e0bd3
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/schneiden_abbrechen.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/tux.png b/skins/nopacity/graphics/menuicons/customicons/tux.png
new file mode 100644
index 0000000..c5b4742
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/tux.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/usb.png b/skins/nopacity/graphics/menuicons/customicons/usb.png
new file mode 100644
index 0000000..c4db1d4
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/usb.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/vdrlogo.png b/skins/nopacity/graphics/menuicons/customicons/vdrlogo.png
new file mode 100644
index 0000000..037a191
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/vdrlogo.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/customicons/yaicon_blue.png b/skins/nopacity/graphics/menuicons/customicons/yaicon_blue.png
new file mode 100644
index 0000000..2c49273
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/customicons/yaicon_blue.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/admin.png b/skins/nopacity/graphics/menuicons/pluginicons/admin.png
new file mode 100644
index 0000000..cf328ef
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/admin.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/arghdirector.png b/skins/nopacity/graphics/menuicons/pluginicons/arghdirector.png
new file mode 100644
index 0000000..bbd221a
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/arghdirector.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/autostart.png b/skins/nopacity/graphics/menuicons/pluginicons/autostart.png
new file mode 100644
index 0000000..6fdb1bb
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/autostart.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/avahi4vdr.png b/skins/nopacity/graphics/menuicons/pluginicons/avahi4vdr.png
new file mode 100644
index 0000000..044e71d
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/avahi4vdr.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/avards.png b/skins/nopacity/graphics/menuicons/pluginicons/avards.png
new file mode 100644
index 0000000..cf8d037
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/avards.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/block.png b/skins/nopacity/graphics/menuicons/pluginicons/block.png
new file mode 100644
index 0000000..86127c2
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/block.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/burn.png b/skins/nopacity/graphics/menuicons/pluginicons/burn.png
new file mode 100644
index 0000000..305d7ff
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/burn.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/cdplayer.png b/skins/nopacity/graphics/menuicons/pluginicons/cdplayer.png
new file mode 100644
index 0000000..89a6c19
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/cdplayer.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/chanman.png b/skins/nopacity/graphics/menuicons/pluginicons/chanman.png
new file mode 100644
index 0000000..a73e83c
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/chanman.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/check.png b/skins/nopacity/graphics/menuicons/pluginicons/check.png
new file mode 100644
index 0000000..d487a24
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/check.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/conflictcheckonly.png b/skins/nopacity/graphics/menuicons/pluginicons/conflictcheckonly.png
new file mode 100644
index 0000000..7f832bd
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/conflictcheckonly.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/ddci.png b/skins/nopacity/graphics/menuicons/pluginicons/ddci.png
new file mode 100644
index 0000000..4ad459c
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/ddci.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/devstatus.png b/skins/nopacity/graphics/menuicons/pluginicons/devstatus.png
new file mode 100644
index 0000000..96c0ec1
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/devstatus.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/dummydevice.png b/skins/nopacity/graphics/menuicons/pluginicons/dummydevice.png
new file mode 100644
index 0000000..11fd707
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/dummydevice.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/duplicates.png b/skins/nopacity/graphics/menuicons/pluginicons/duplicates.png
new file mode 100644
index 0000000..dc1be57
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/duplicates.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/dvbapi.png b/skins/nopacity/graphics/menuicons/pluginicons/dvbapi.png
new file mode 100644
index 0000000..b966461
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/dvbapi.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/dvbhddevice.png b/skins/nopacity/graphics/menuicons/pluginicons/dvbhddevice.png
new file mode 100644
index 0000000..b874297
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/dvbhddevice.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/dvbsddevice.png b/skins/nopacity/graphics/menuicons/pluginicons/dvbsddevice.png
new file mode 100644
index 0000000..106184e
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/dvbsddevice.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/dynamite.png b/skins/nopacity/graphics/menuicons/pluginicons/dynamite.png
new file mode 100644
index 0000000..28ea35a
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/dynamite.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/eepg.png b/skins/nopacity/graphics/menuicons/pluginicons/eepg.png
new file mode 100644
index 0000000..3938b96
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/eepg.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/epg2vdr.png b/skins/nopacity/graphics/menuicons/pluginicons/epg2vdr.png
new file mode 100644
index 0000000..ac8757e
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/epg2vdr.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/epgsearch.png b/skins/nopacity/graphics/menuicons/pluginicons/epgsearch.png
new file mode 100644
index 0000000..5eab415
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/epgsearch.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/epgsearchonly.png b/skins/nopacity/graphics/menuicons/pluginicons/epgsearchonly.png
new file mode 100644
index 0000000..b5186e7
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/epgsearchonly.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/epgsync.png b/skins/nopacity/graphics/menuicons/pluginicons/epgsync.png
new file mode 100644
index 0000000..5c14009
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/epgsync.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/externalplayer.png b/skins/nopacity/graphics/menuicons/pluginicons/externalplayer.png
new file mode 100644
index 0000000..2bd67db
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/externalplayer.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/extrecmenu.png b/skins/nopacity/graphics/menuicons/pluginicons/extrecmenu.png
new file mode 100644
index 0000000..6f613f1
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/extrecmenu.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/favorites.png b/skins/nopacity/graphics/menuicons/pluginicons/favorites.png
new file mode 100644
index 0000000..409c852
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/favorites.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/femon.png b/skins/nopacity/graphics/menuicons/pluginicons/femon.png
new file mode 100644
index 0000000..e87b711
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/femon.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/fepg.png b/skins/nopacity/graphics/menuicons/pluginicons/fepg.png
new file mode 100644
index 0000000..65023ed
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/fepg.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/filebrowser.png b/skins/nopacity/graphics/menuicons/pluginicons/filebrowser.png
new file mode 100644
index 0000000..d3f90e0
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/filebrowser.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/fritzbox.png b/skins/nopacity/graphics/menuicons/pluginicons/fritzbox.png
new file mode 100644
index 0000000..7bfc229
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/fritzbox.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/graphlcd.png b/skins/nopacity/graphics/menuicons/pluginicons/graphlcd.png
new file mode 100644
index 0000000..39ffd35
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/graphlcd.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/graphtft.png b/skins/nopacity/graphics/menuicons/pluginicons/graphtft.png
new file mode 100644
index 0000000..39ffd35
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/graphtft.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/image.png b/skins/nopacity/graphics/menuicons/pluginicons/image.png
new file mode 100644
index 0000000..33644e0
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/image.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/imonlcd.png b/skins/nopacity/graphics/menuicons/pluginicons/imonlcd.png
new file mode 100644
index 0000000..3d34fc4
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/imonlcd.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/iptv.png b/skins/nopacity/graphics/menuicons/pluginicons/iptv.png
new file mode 100644
index 0000000..4494ddc
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/iptv.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/lcdproc.png b/skins/nopacity/graphics/menuicons/pluginicons/lcdproc.png
new file mode 100644
index 0000000..3d34fc4
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/lcdproc.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/mailbox.png b/skins/nopacity/graphics/menuicons/pluginicons/mailbox.png
new file mode 100644
index 0000000..1bc76e8
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/mailbox.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/makemkv.png b/skins/nopacity/graphics/menuicons/pluginicons/makemkv.png
new file mode 100644
index 0000000..41cddf1
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/makemkv.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/markad.png b/skins/nopacity/graphics/menuicons/pluginicons/markad.png
new file mode 100644
index 0000000..b3defaf
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/markad.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/mlist.png b/skins/nopacity/graphics/menuicons/pluginicons/mlist.png
new file mode 100644
index 0000000..19c367f
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/mlist.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/music.png b/skins/nopacity/graphics/menuicons/pluginicons/music.png
new file mode 100644
index 0000000..abb012e
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/music.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/noepg.png b/skins/nopacity/graphics/menuicons/pluginicons/noepg.png
new file mode 100644
index 0000000..eb9410d
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/noepg.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/nordlichtsepg.png b/skins/nopacity/graphics/menuicons/pluginicons/nordlichtsepg.png
new file mode 100644
index 0000000..3ee3fa2
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/nordlichtsepg.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/osdteletext.png b/skins/nopacity/graphics/menuicons/pluginicons/osdteletext.png
new file mode 100644
index 0000000..664e770
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/osdteletext.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/peer.png b/skins/nopacity/graphics/menuicons/pluginicons/peer.png
new file mode 100644
index 0000000..998d568
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/peer.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/play.png b/skins/nopacity/graphics/menuicons/pluginicons/play.png
new file mode 100644
index 0000000..2848fc6
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/play.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/pvrinput.png b/skins/nopacity/graphics/menuicons/pluginicons/pvrinput.png
new file mode 100644
index 0000000..724f698
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/pvrinput.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/quickepgsearch.png b/skins/nopacity/graphics/menuicons/pluginicons/quickepgsearch.png
new file mode 100644
index 0000000..76a31f4
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/quickepgsearch.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/radio.png b/skins/nopacity/graphics/menuicons/pluginicons/radio.png
new file mode 100644
index 0000000..193b7d4
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/radio.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/remote.png b/skins/nopacity/graphics/menuicons/pluginicons/remote.png
new file mode 100644
index 0000000..7f46b1b
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/remote.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/remotetimers.png b/skins/nopacity/graphics/menuicons/pluginicons/remotetimers.png
new file mode 100644
index 0000000..fae3b79
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/remotetimers.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/rssreader.png b/skins/nopacity/graphics/menuicons/pluginicons/rssreader.png
new file mode 100644
index 0000000..db538f0
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/rssreader.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/sc.png b/skins/nopacity/graphics/menuicons/pluginicons/sc.png
new file mode 100644
index 0000000..2472d6c
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/sc.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/screenshot.png b/skins/nopacity/graphics/menuicons/pluginicons/screenshot.png
new file mode 100644
index 0000000..be9b4d5
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/screenshot.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/seduatmo.png b/skins/nopacity/graphics/menuicons/pluginicons/seduatmo.png
new file mode 100644
index 0000000..4b5292f
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/seduatmo.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/skyselectfeeds.png b/skins/nopacity/graphics/menuicons/pluginicons/skyselectfeeds.png
new file mode 100644
index 0000000..d81a024
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/skyselectfeeds.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/sleeptimer.png b/skins/nopacity/graphics/menuicons/pluginicons/sleeptimer.png
new file mode 100644
index 0000000..cd4956f
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/sleeptimer.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/softhddevice.png b/skins/nopacity/graphics/menuicons/pluginicons/softhddevice.png
new file mode 100644
index 0000000..df13f2c
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/softhddevice.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/streamdev-server.png b/skins/nopacity/graphics/menuicons/pluginicons/streamdev-server.png
new file mode 100644
index 0000000..e89ed8b
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/streamdev-server.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/systeminfo.png b/skins/nopacity/graphics/menuicons/pluginicons/systeminfo.png
new file mode 100644
index 0000000..b14763f
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/systeminfo.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/targavfd.png b/skins/nopacity/graphics/menuicons/pluginicons/targavfd.png
new file mode 100644
index 0000000..e91b111
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/targavfd.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/trayopenng.png b/skins/nopacity/graphics/menuicons/pluginicons/trayopenng.png
new file mode 100644
index 0000000..6ebd17d
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/trayopenng.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/tvguide.png b/skins/nopacity/graphics/menuicons/pluginicons/tvguide.png
new file mode 100644
index 0000000..968a37c
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/tvguide.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/tvm2vdr.png b/skins/nopacity/graphics/menuicons/pluginicons/tvm2vdr.png
new file mode 100644
index 0000000..47f9a91
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/tvm2vdr.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/tvscraper.png b/skins/nopacity/graphics/menuicons/pluginicons/tvscraper.png
new file mode 100644
index 0000000..a106cb5
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/tvscraper.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/undelete.png b/skins/nopacity/graphics/menuicons/pluginicons/undelete.png
new file mode 100644
index 0000000..a53d50a
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/undelete.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/weatherng.png b/skins/nopacity/graphics/menuicons/pluginicons/weatherng.png
new file mode 100644
index 0000000..a88f11d
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/weatherng.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/xmltv2vdr.png b/skins/nopacity/graphics/menuicons/pluginicons/xmltv2vdr.png
new file mode 100644
index 0000000..ea73c74
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/xmltv2vdr.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/pluginicons/yaepghg.png b/skins/nopacity/graphics/menuicons/pluginicons/yaepghg.png
new file mode 100644
index 0000000..53ce443
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/pluginicons/yaepghg.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/CAM.png b/skins/nopacity/graphics/menuicons/standardicons/CAM.png
new file mode 100644
index 0000000..a394877
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/CAM.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/Channels.png b/skins/nopacity/graphics/menuicons/standardicons/Channels.png
new file mode 100644
index 0000000..ba2ba78
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/Channels.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/Commands.png b/skins/nopacity/graphics/menuicons/standardicons/Commands.png
new file mode 100644
index 0000000..c6a83ef
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/Commands.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/DVB.png b/skins/nopacity/graphics/menuicons/standardicons/DVB.png
new file mode 100644
index 0000000..3789145
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/DVB.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/EPG.png b/skins/nopacity/graphics/menuicons/standardicons/EPG.png
new file mode 100644
index 0000000..e868b90
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/EPG.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/LNB.png b/skins/nopacity/graphics/menuicons/standardicons/LNB.png
new file mode 100644
index 0000000..896dd99
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/LNB.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/Miscellaneous.png b/skins/nopacity/graphics/menuicons/standardicons/Miscellaneous.png
new file mode 100644
index 0000000..2a41c4d
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/Miscellaneous.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/OSD.png b/skins/nopacity/graphics/menuicons/standardicons/OSD.png
new file mode 100644
index 0000000..8f571c6
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/OSD.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/Plugins.png b/skins/nopacity/graphics/menuicons/standardicons/Plugins.png
new file mode 100644
index 0000000..3fcba70
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/Plugins.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/Recording.png b/skins/nopacity/graphics/menuicons/standardicons/Recording.png
new file mode 100644
index 0000000..741b1af
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/Recording.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/Recordings.png b/skins/nopacity/graphics/menuicons/standardicons/Recordings.png
new file mode 100644
index 0000000..79aeeb7
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/Recordings.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/Replay.png b/skins/nopacity/graphics/menuicons/standardicons/Replay.png
new file mode 100644
index 0000000..621596c
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/Replay.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/Restart.png b/skins/nopacity/graphics/menuicons/standardicons/Restart.png
new file mode 100644
index 0000000..aa23cd4
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/Restart.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/Schedule.png b/skins/nopacity/graphics/menuicons/standardicons/Schedule.png
new file mode 100644
index 0000000..3a98cac
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/Schedule.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/Setup.png b/skins/nopacity/graphics/menuicons/standardicons/Setup.png
new file mode 100644
index 0000000..d121148
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/Setup.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/StopRecording.png b/skins/nopacity/graphics/menuicons/standardicons/StopRecording.png
new file mode 100644
index 0000000..ed83fbb
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/StopRecording.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/StopReplay.png b/skins/nopacity/graphics/menuicons/standardicons/StopReplay.png
new file mode 100644
index 0000000..9192760
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/StopReplay.png
Binary files differ
diff --git a/skins/nopacity/graphics/menuicons/standardicons/Timers.png b/skins/nopacity/graphics/menuicons/standardicons/Timers.png
new file mode 100644
index 0000000..b866c36
--- /dev/null
+++ b/skins/nopacity/graphics/menuicons/standardicons/Timers.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/buttonblue.png b/skins/nopacity/graphics/skinparts/buttonblue.png
new file mode 100644
index 0000000..d00e4d2
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/buttonblue.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/buttongreen.png b/skins/nopacity/graphics/skinparts/buttongreen.png
new file mode 100644
index 0000000..8c05c08
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/buttongreen.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/buttonred.png b/skins/nopacity/graphics/skinparts/buttonred.png
new file mode 100644
index 0000000..9367c9b
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/buttonred.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/buttonyellow.png b/skins/nopacity/graphics/skinparts/buttonyellow.png
new file mode 100644
index 0000000..aff8758
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/buttonyellow.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/channellogoback.png b/skins/nopacity/graphics/skinparts/channellogoback.png
new file mode 100644
index 0000000..b0e83b1
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/channellogoback.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/discpercent.png b/skins/nopacity/graphics/skinparts/discpercent.png
new file mode 100644
index 0000000..cf32be2
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/discpercent.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/displaychannelback.png b/skins/nopacity/graphics/skinparts/displaychannelback.png
new file mode 100644
index 0000000..1437384
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/displaychannelback.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/displaychanneltop.png b/skins/nopacity/graphics/skinparts/displaychanneltop.png
new file mode 100644
index 0000000..5108435
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/displaychanneltop.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/displayreplayback.png b/skins/nopacity/graphics/skinparts/displayreplayback.png
new file mode 100644
index 0000000..d72931f
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/displayreplayback.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/displayreplaytop.png b/skins/nopacity/graphics/skinparts/displayreplaytop.png
new file mode 100644
index 0000000..064347e
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/displayreplaytop.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/displayvolume.png b/skins/nopacity/graphics/skinparts/displayvolume.png
new file mode 100644
index 0000000..a5c4c66
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/displayvolume.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/headertop.png b/skins/nopacity/graphics/skinparts/headertop.png
new file mode 100644
index 0000000..2bc19a6
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/headertop.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/menubutton.png b/skins/nopacity/graphics/skinparts/menubutton.png
new file mode 100644
index 0000000..0800a5e
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/menubutton.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/menubuttonactive.png b/skins/nopacity/graphics/skinparts/menubuttonactive.png
new file mode 100644
index 0000000..caae104
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/menubuttonactive.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/menubuttondefault.png b/skins/nopacity/graphics/skinparts/menubuttondefault.png
new file mode 100644
index 0000000..76735de
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/menubuttondefault.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/menubuttondefaultactive.png b/skins/nopacity/graphics/skinparts/menubuttondefaultactive.png
new file mode 100644
index 0000000..70c0b8a
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/menubuttondefaultactive.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/menubuttontop.png b/skins/nopacity/graphics/skinparts/menubuttontop.png
new file mode 100644
index 0000000..1b49cfd
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/menubuttontop.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/messageError.png b/skins/nopacity/graphics/skinparts/messageError.png
new file mode 100644
index 0000000..a894992
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/messageError.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/messageInfo.png b/skins/nopacity/graphics/skinparts/messageInfo.png
new file mode 100644
index 0000000..5f8e62a
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/messageInfo.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/messageStatus.png b/skins/nopacity/graphics/skinparts/messageStatus.png
new file mode 100644
index 0000000..f4b83f4
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/messageStatus.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/messageWarning.png b/skins/nopacity/graphics/skinparts/messageWarning.png
new file mode 100644
index 0000000..f073ed5
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/messageWarning.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/scrollbar.png b/skins/nopacity/graphics/skinparts/scrollbar.png
new file mode 100644
index 0000000..f822555
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/scrollbar.png
Binary files differ
diff --git a/skins/nopacity/graphics/skinparts/signal.png b/skins/nopacity/graphics/skinparts/signal.png
new file mode 100644
index 0000000..4f03c7a
--- /dev/null
+++ b/skins/nopacity/graphics/skinparts/signal.png
Binary files differ
diff --git a/skins/nopacity/xmlfiles/displayaudiotracks.xml b/skins/nopacity/xmlfiles/displayaudiotracks.xml
new file mode 100644
index 0000000..688f374
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displayaudiotracks.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displayaudiotracks SYSTEM "../../dtd/displayaudiotracks.dtd">
+
+<displayaudiotracks x="25%" y="0" width="50%" height="100%" fadetime="{fadeTime}">
+ <!-- Available Variables background:
+ {numtracks} number of displayed tracks
+ -->
+ <background>
+ <area x="0" y="{areaheight} - {numtracks} * {areaheight} / 10 - {areaheight} / 10" width="100%" height="{areaheight} / 10 + {areaheight} / 10 * {numtracks}" layer="1">
+ <fill color="{clrTransBlack}" />
+ </area>
+ </background>
+
+ <!-- Available Variables header:
+ {numtracks} number of displayed tracks
+ {title} title of menu
+ -->
+ <header>
+ <area x="0" y="{areaheight} - {numtracks} * {areaheight} / 10 - {areaheight} / 10" width="100%" height="{areaheight} / 10" layer="2">
+ <drawtext x="10" valign="center" font="{vdrOsd}" fontsize="80%" color="{clrWhite}" text="{title}" />
+ <drawimage condition="{isstereo}" imagetype="icon" path="ico_stereo" x="{areawidth} - {areaheight}*0.9" valign="center" width="{areaheight}*0.9" height="{areaheight}*0.9"/>
+ <drawimage condition="{isac3}" imagetype="icon" path="ico_ac3" x="{areawidth} - {areaheight}*0.9" valign="center" width="{areaheight}*0.9" height="{areaheight}*0.9"/>
+ </area>
+ </header>
+
+ <!-- Available Variables header:
+ {numelements} number of displayed tracks
+ -->
+ <menuitems x="0" y="{areaheight} - {numelements} * {areaheight} / 10" orientation="vertical" width="100%" height="{numelements} * {areaheight} / 10" align="top" numlistelements="{numelements}">
+ <!-- Available Variables auidotrack listelement:
+ {current} true if item is currently selected
+ {title} title of auio track
+ -->
+ <listelement>
+ <!-- Background -->
+ <area x="1%" width="98%" layer="2">
+ <drawimage condition="not{current}" imagetype="skinpart" path="menubutton" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ <drawimage condition="{current}" imagetype="skinpart" path="menubuttonactive" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ </area>
+ <area x="1%" width="98%" layer="3">
+ <drawtext x="10" valign="center" font="{vdrOsd}" fontsize="60%" color="{clrWhite}" text="{title}" />
+ </area>
+ </listelement>
+ </menuitems>
+
+</displayaudiotracks>
diff --git a/skins/nopacity/xmlfiles/displaychannel.xml b/skins/nopacity/xmlfiles/displaychannel.xml
new file mode 100644
index 0000000..8355f84
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displaychannel.xml
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displaychannel SYSTEM "../../dtd/displaychannel.dtd">
+
+<displaychannel x="0" y="0" width="100%" height="100%" fadetime="{fadeTime}">
+
+ <background>
+ <area x="1%" y="74%" width="98%" height="25%" layer="1" transparency="20">
+ <drawimage imagetype="skinpart" path="displaychannelback" x="0" y="0" width="100%" height="100%"/>
+ </area>
+ <area x="1%" y="74%" width="98%" height="25%" layer="7">
+ <drawimage imagetype="skinpart" path="displaychanneltop" x="0" y="0" width="100%" height="100%"/>
+ </area>
+ <area x="2%" y="80%" width="14%" height="18%" layer="2">
+ <drawimage imagetype="skinpart" path="channellogoback" x="0" y="0" width="100%" height="100%"/>
+ </area>
+ </background>
+ <!-- Available Variables channelinfo:
+ {channelnumber} Number of Channel, with "-" in case of channel switching
+ {channelname} Name of current Channel
+ {channellogoexists} true if a channel logo exists
+ {channelid} ChannelID as path to display channel logo
+ {switching} true if a number is pressed on the remote to switch to a dedicated channel
+ -->
+ <channelinfo>
+ <area x="2%" y="80%" width="14%" height="18%" layer="2">
+ <drawimage cache="true" imagetype="channellogo" path="{channelid}" height="98%" align="center" valign="center"/>
+ </area>
+ <area x="18%" y="74%" width="60%" height="6%" layer="2">
+ <drawtext x="0" valign="center" font="{vdrOsd}" fontsize="95%" color="{clrWhite}" text="{channelnumber} {channelname}" />
+ </area>
+ </channelinfo>
+
+ <!-- Available Variables datetime:
+ {time} time in hh:mm
+ {day} day in digits
+ {dayleadingzero} day in digits with leading 0
+ {dayname} Full name of the day
+ {daynameshort} Short 3 char name of the day
+ {month} month in digits with leading 0
+ {monthname} Full name of the month
+ {year} year in yyyy
+ -->
+ <datetime>
+ <area x="78%" y="74%" width="20%" height="6%" layer="2">
+ <drawtext align="right" valign="center" font="{vdrOsd}" fontsize="70%" color="{clrWhite}" text="{daynameshort} {day}.{month} {time}" />
+ </area>
+ </datetime>
+
+ <!-- Available Variables epginfo:
+ {currenttitle} Title of the current Schedule
+ {currentsubtitle} Subtitle of the current Schedule
+ {currentstart} Start of current Schedule in hh:mm
+ {currentstop} End of current Schedule in hh:mm
+ {currentduration} Duration of current Schedule in min
+ {currentelapsed} Elapsed time of current Schedule in min
+ {currentremaining} Remaining time of current Schedule in min
+ {currentrecording} true if current Schedule is recorded
+ {nexttitle} Title of next Schedule
+ {nextsubtitle} Subtitle of next Schedule
+ {nextstart} Start of next Schedule in hh:mm
+ {nextstop} Stop of next Schedule in hh:mm
+ {nextduration} Duration of next Schedule in min
+ {nextrecording} true if next Schedule will be recorded
+ -->
+ <epginfo>
+ <area x="18%" y="82%" width="68%" height="6%" layer="2">
+ <drawtext name="starttime" x="0" y="0" font="{vdrOsd}" fontsize="60%" color="{clrWhite}" text="{currentstart}" />
+ <drawtext x="{width(starttime)} + 15" y="0" width="{areawidth} - {width(starttime)} - 15" font="{vdrOsd}" fontsize="60%" color="{clrWhite}" text="{currenttitle}" />
+ <drawtext x="{width(starttime)} + 16" y="55%" width="{areawidth} - {width(starttime)} - 16" font="{vdrOsd}" fontsize="45%" color="{clrWhite}" text="{currentsubtitle}" />
+ </area>
+ <area x="86%" y="82%" width="11%" height="6%" layer="2">
+ <drawtext align="right" y="0" font="{vdrOsd}" fontsize="60%" color="{clrWhite}" text="{currentelapsed}/{currentduration}min" />
+ </area>
+ <area x="18%" y="88%" width="72%" height="6%" layer="2">
+ <drawtext name="starttime" x="0" y="0" font="{vdrOsd}" fontsize="60%" color="{clrGray}" text="{nextstart}" />
+ <drawtext x="{width(starttime)} + 15" y="0" width="{areawidth} - {width(starttime)} - 15" font="{vdrOsd}" fontsize="60%" color="{clrGray}" text="{nexttitle}" />
+ <drawtext x="{width(starttime)} + 16" y="55%" width="{areawidth} - {width(starttime)} - 16" font="{vdrOsd}" fontsize="45%" color="{clrGray}" text="{nextsubtitle}" />
+ </area>
+ <area x="90%" y="88%" width="7%" height="6%" layer="2">
+ <drawtext align="right" y="0" font="{vdrOsd}" fontsize="60%" color="{clrGray}" text="{nextduration}min" />
+ </area>
+ </epginfo>
+
+ <!-- Available Variables progressbar:
+ {start} Start of current Schedule in hh:mm
+ {stop} End of current Schedule in hh:mm
+ {duration} Total Duration of current Schedule in seconds
+ {elapsed} Elapsed time of current Schedule in seconds
+ {remaining} Remaining time of current Schedule in seconds
+ -->
+ <progressbar>
+ <area x="17%" y="80%" width="81%" height="2%" layer="2">
+ <drawellipse x="1" y="1" width="{areaheight}-2" height="{areaheight}-2" color="{clrBrightGreen}" quadrant="0" />
+ <drawellipse x="1 + {elapsed}/{duration}*{areawidth} - {elapsed}/{duration}*{areaheight}" y="1" width="{areaheight}-2" height="{areaheight}-2" color="{clrBrightGreen}" quadrant="0" />
+ <drawrectangle x="{areaheight}/2" y="1" width="{elapsed}/{duration}*{areawidth} - {elapsed}/{duration}*{areaheight}" height="{areaheight}-2" color="{clrBrightGreen}" />
+ </area>
+ </progressbar>
+
+ <progressbarback>
+ <area x="17%" y="80%" width="81%" height="2%" layer="2">
+ <drawellipse x="0" y="0" width="{areaheight}" height="{areaheight}" color="{clrBlack}" quadrant="0" />
+ <drawellipse x="{areawidth}-{areaheight}" y="0" width="{areaheight}" height="{areaheight}" color="{clrBlack}" quadrant="0" />
+ <drawrectangle x="{areaheight}/2" y="0" width="{areawidth} - {areaheight}" height="{areaheight}" color="{clrBlack}" />
+ </area>
+ </progressbarback>
+ <!-- Available Variables statusinfo:
+ {isRadio} true if channel is a radio channel
+ {hasVT} true if channel has video text
+ {isStereo} true if a stereo audio trac is available
+ {isDolby} true if a dolby audio track is available
+ {isEncrypted} true if channel is encrypted
+ {isRecording} true if currently a recording is running on this channel
+ -->
+ <statusinfo>
+ <area x="{areawidth}*0.98 - {areaheight}*0.40 - 25" y="93%" width="{areaheight}*0.25 + 20" height="5%" layer="2">
+ <drawimage condition="{hasVT}" imagetype="icon" path="ico_txton" x="0" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="not{hasVT}" imagetype="icon" path="ico_txtoff" x="0" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{isStereo}" imagetype="icon" path="ico_stereoon" x="{areaheight}+5" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="not{isStereo}" imagetype="icon" path="ico_stereooff" x="{areaheight}+5" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{isDolby}" imagetype="icon" path="ico_dolbyon" x="2*{areaheight}+10" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="not{isDolby}" imagetype="icon" path="ico_dolbyoff" x="2*{areaheight}+10" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{isEncrypted}" imagetype="icon" path="ico_encrypted" x="3*{areaheight}+15" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="not{isEncrypted}" imagetype="icon" path="ico_fta" x="3*{areaheight}+15" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{isRecording}" imagetype="icon" path="ico_recon" x="4*{areaheight}+20" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="not{isRecording}" imagetype="icon" path="ico_recoff" x="4*{areaheight}+20" y="0" width="{areaheight}" height="{areaheight}"/>
+ </area>
+ </statusinfo>
+
+ <!-- Available Variables screenresolution:
+ {screenwidth} width of currently displayed channel in px
+ {screenheight} height of currently displayed channel in px
+ {resolution} resolution: hd1080i, hd720p, sd576i
+ {aspect} screen aspect, each 4:3, 16:9 or 21:9
+ {isHD} true for hd1080i and hd720p
+ {isWideScreen} true if aspect is 16:9 or 21:9
+ -->
+ <screenresolution>
+ <area x="{areawidth}*0.98 - {areaheight}*0.15" y="93%" width="{areaheight}*0.15" height="5%" layer="2">
+ <drawimage imagetype="icon" path="ico_{resolution}" x="0" y="0" width="{areaheight}*3" height="{areaheight}"/>
+ </area>
+ </screenresolution>
+
+ <!-- Available Variables dvbdeviceinfo:
+ {prevAvailable} true if previous Channel Group is avaialble
+ {nextAvailable} true if next Channel Group is avaialble
+ {group} Name of current Channel Group
+ {nextgroup} Name of next Channel Group
+ {prevgroup} Name of prev Channel Group
+ {sepexists} true if a channel separator logo exists
+ {seppath} path for separator logo to use in imagetype "seplogo"
+ -->
+ <channelgroup>
+ <area x="2%" y="80%" width="14%" height="18%" layer="2">
+ <drawimage condition="{sepexists}" imagetype="seplogo" path="{seppath}" height="98%" align="center" valign="center" />
+ <drawimage condition="not{sepexists}" imagetype="icon" path="ico_channelsep" align="center" valign="center" width="{areaheight}*0.8" height="{areaheight}*0.8"/>
+ </area>
+ <area x="18%" y="82%" width="80%" height="10%" layer="2">
+ <drawtext x="0" width="25%" valign="center" font="{vdrOsd}" fontsize="60%" color="{clrWhite}" text="{prevgroup}" />
+ <drawtext x="30%" width="40%" valign="center" font="{vdrOsd}" fontsize="80%" color="{clrWhite}" text="{group}" />
+ <drawtext align="right" width="25%" valign="center" font="{vdrOsd}" fontsize="60%" color="{clrWhite}" text="{nextgroup}" />
+ <drawimage imagetype="icon" path="ico_arrow_left_channelsep" x="25%" valign="center" width="{areawidth}*4/100" height="{areawidth}*4/100"/>
+ <drawimage imagetype="icon" path="ico_arrow_right_channelsep" x="71%" valign="center" width="{areawidth}*4/100" height="{areawidth}*4/100"/>
+ </area>
+ </channelgroup>
+ <!-- Available Variables signalquality:
+ {signalstrength} STR value of currently displayed channel
+ {signalquality} SNR value of currently displayed channel
+ -->
+ <signalquality>
+ <area x="17%" y="95%" width="15%" height="4%" layer="3">
+ <drawrectangle x="{areawidth}*{signalstrength}/100" y="0" width="{areawidth} - {areawidth}*{signalstrength}/100" height="45%" color="{clrTransBlack}" />
+ <drawrectangle x="{areawidth}*{signalquality}/100" y="50%" width="{areawidth} - {areawidth}*{signalquality}/100" height="45%" color="{clrTransBlack}" />
+ </area>
+ </signalquality>
+
+ <!-- background of signalmeter, will only be drawn if signalquality was deleted -->
+ <signalqualityback>
+ <area x="17%" y="95%" width="15%" height="4%" layer="2">
+ <drawimage imagetype="skinpart" path="signal" x="0" y="0" width="100%" height="45%"/>
+ <drawimage imagetype="skinpart" path="signal" x="0" y="50%" width="100%" height="45%"/>
+ </area>
+ </signalqualityback>
+
+ <!-- Available Variables scrapercontent:
+ {mediapath} Full Path of Poster or Banner to use in image path attribute
+ {mediawidth} width of image in pixel
+ {mediaheight} height of image in pixel
+ {isbanner} true if image is a banner, false if it is a poster
+ -->
+ <scrapercontent>
+ <area condition="{isbanner}" x="1%" y="1%" width="{areaheight}*0.13*{mediawidth}/{mediaheight}" height="13%" layer="2">
+ <drawimage imagetype="image" path="{mediapath}" align="center" valign="center" width="{areawidth}" height="{areaheight}"/>
+ </area>
+ <area condition="not{isbanner}" x="1%" y="1%" width="{areaheight}*0.5*{mediawidth}/{mediaheight}" height="50%" layer="2">
+ <drawimage imagetype="image" path="{mediapath}" x="5" y="5" width="{areawidth}-10" height="{areaheight}-10"/>
+ </area>
+ </scrapercontent>
+
+ <!-- Available Variables message:
+ {text} message text
+ {status} true if message is a status message
+ {info} true if message is a info message
+ {warning} true if message is a warn message
+ {error} true if message is a error message
+ -->
+ <message>
+ <area x="5%" y="58%" width="90%" height="15%" layer="6">
+ <drawimage condition="{status}" imagetype="skinpart" path="messageStatus" x="0" y="0" width="100%" height="100%" />
+ <drawimage condition="{info}" imagetype="skinpart" path="messageInfo" x="0" y="0" width="100%" height="100%" />
+ <drawimage condition="{warning}" imagetype="skinpart" path="messageWarning" x="0" y="0" width="100%" height="100%" />
+ <drawimage condition="{error}" imagetype="skinpart" path="messageError" x="0" y="0" width="100%" height="100%" />
+ </area>
+ <area x="5%" y="58%" width="90%" height="15%" layer="7">
+ <drawtext align="center" valign="center" font="{light}" fontsize="40%" color="{clrWhite}" text="{text}" />
+ </area>
+ </message>
+
+</displaychannel>
diff --git a/skins/nopacity/xmlfiles/displaymenu.xml b/skins/nopacity/xmlfiles/displaymenu.xml
new file mode 100644
index 0000000..f70f6d2
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displaymenu.xml
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displaymenu SYSTEM "../../dtd/displaymenu.dtd" [
+<!ENTITY displaymenudefault SYSTEM "displaymenudefault.xml">
+<!ENTITY displaymenumain SYSTEM "displaymenumain.xml">
+<!ENTITY displaymenusetup SYSTEM "displaymenusetup.xml">
+<!ENTITY displaymenuschedules SYSTEM "displaymenuschedules.xml">
+<!ENTITY displaymenutimers SYSTEM "displaymenutimers.xml">
+<!ENTITY displaymenuchannels SYSTEM "displaymenuchannels.xml">
+<!ENTITY displaymenurecordings SYSTEM "displaymenurecordings.xml">
+<!ENTITY displaymenudetailepg SYSTEM "displaymenudetailepg.xml">
+<!ENTITY displaymenudetailrecording SYSTEM "displaymenudetailrecording.xml">
+<!ENTITY displaymenudetailtext SYSTEM "displaymenudetailtext.xml">
+]>
+
+<displaymenu x="0" y="0" width="100%" height="100%" fadetime="0">
+ <!--
+ The following background, header, datetime and colorbuttons definitions are default
+ implementations. If one or more of these elements are not implemented in the subview,
+ the default implementations are used.
+ -->
+ <background>
+ <area x="0" y="0" width="100%" height="100%" layer="1">
+ <!-- top bar -->
+ <drawrectangle x="0" y="0" width="{areawidth}" height="10%" color="{clrDarkBlue}" />
+ <drawrectangle x="30%" y="{areaheight}*0.1 - 1" width="71%" height="1" color="{clrDarkGreen}" />
+ <!-- menu bar -->
+ <drawrectangle x="0" y="10%" width="{areawidth}*29/100" height="81%" color="{clrDarkBlue}" />
+ <drawrectangle x="{areawidth}*29/100 - 1" y="12%" width="1" height="76%" color="{clrDarkGreen}" />
+ <!-- bottom bar -->
+ <drawrectangle x="0" y="90%" width="{areawidth}" height="10%" color="{clrDarkBlue}" />
+ <drawrectangle x="30%" y="{areaheight}*0.9 - 1" width="71%" height="1" color="{clrDarkGreen}" />
+ <!-- upper corner -->
+ <drawellipse x="{areawidth}*29/100" y="{areaheight}/10" width="{areawidth}*2/100" height="{areawidth}*2/100" quadrant="-2" color="{clrDarkGreen}" />
+ <drawellipse x="{areawidth}*29/100 - 1" y="{areaheight}/10 - 1" width="{areawidth}*2/100" height="{areawidth}*2/100" quadrant="-2" color="{clrDarkBlue}" />
+ <!-- lower corner -->
+ <drawellipse x="{areawidth}*29/100" y="{areaheight}*90/100 - {areawidth}*2/100" width="{areawidth}*2/100" height="{areawidth}*2/100" quadrant="-3" color="{clrDarkGreen}" />
+ <drawellipse x="{areawidth}*29/100 - 1" y="{areaheight}*90/100 - {areawidth}*2/100 + 1" width="{areawidth}*2/100" height="{areawidth}*2/100" quadrant="-3" color="{clrDarkBlue}" />
+ </area>
+ <area x="0" y="0" width="100%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="headertop" x="0" y="0" width="100%" height="100%"/>
+ </area>
+ </background>
+ <!-- Available Variables header:
+ {title} title of current menu
+ {vdrversion} running VDR Version
+ {hasicon} true if a menu icon is available
+ {icon} path of menu icon
+ -->
+ <header>
+ <area x="1%" y="0" width="64%" height="10%" layer="3">
+ <drawtext x="0" valign="center" font="{vdrOsd}" fontsize="50%" color="{clrWhite}" text="{title}" />
+ </area>
+ </header>
+ <!-- Available Variables datetime:
+ {time} time in hh:mm
+ {day} day in digits
+ {dayleadingzero} day in digits with leading 0
+ {dayname} Full name of the day
+ {daynameshort} Short 3 char name of the day
+ {month} month in digits with leading 0
+ {monthname} Full name of the month
+ {year} year in yyyy
+ -->
+ <datetime>
+ <area x="65%" y="0" width="34%" height="10%" layer="3">
+ <drawtext align="right" valign="center" font="{vdrOsd}" fontsize="50%" color="{clrWhite}" text="{daynameshort} {day}.{month} {time}" />
+ </area>
+ </datetime>
+ <!-- Available Variables message:
+ {text} message text
+ {status} true if message is an status message
+ {info} true if message is an info message
+ {warning} true if message is an warn message
+ {error} true if message is an error message
+ -->
+ <message>
+ <area x="5%" y="80%" width="90%" height="15%" layer="6">
+ <drawimage condition="{status}" imagetype="skinpart" path="messageStatus" x="0" y="0" width="100%" height="100%" />
+ <drawimage condition="{info}" imagetype="skinpart" path="messageInfo" x="0" y="0" width="100%" height="100%" />
+ <drawimage condition="{warning}" imagetype="skinpart" path="messageWarning" x="0" y="0" width="100%" height="100%" />
+ <drawimage condition="{error}" imagetype="skinpart" path="messageError" x="0" y="0" width="100%" height="100%" />
+ </area>
+ <area x="5%" y="80%" width="90%" height="15%" layer="7">
+ <drawtext align="center" valign="center" font="{light}" fontsize="40%" color="{clrWhite}" text="{text}" />
+ </area>
+ </message>
+ <!-- Available Variables colorbuttons:
+ {red1} true if red button is button 1
+ {red2} true if red button is button 2
+ {red3} true if red button is button 3
+ {red4} true if red button is button 4
+ {green1} true if green button is button 1
+ {green2} true if green button is button 2
+ {green3} true if green button is button 3
+ {green4} true if green button is button 4
+ {yellow1} true if yellow button is button 1
+ {yellow2} true if yellow button is button 2
+ {yellow3} true if yellow button is button 3
+ {yellow4} true if yellow button is button 4
+ {blue1} true if blue button is button 1
+ {blue2} true if blue button is button 2
+ {blue3} true if blue button is button 3
+ {blue4} true if blue button is button 4
+ {red} label of red button
+ {green} label of green button
+ {yellow} label of yellow button
+ {blue} label of blue button
+ -->
+ <colorbuttons>
+ <area condition="{red1}" x="0" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttonred" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{red}" />
+ </area>
+ <area condition="{green1}" x="0" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttongreen" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{green}" />
+ </area>
+ <area condition="{yellow1}" x="0" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttonyellow" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{yellow}" />
+ </area>
+ <area condition="{blue1}" x="0" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttonblue" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{blue}" />
+ </area>
+
+ <area condition="{red2}" x="25%" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttonred" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{red}" />
+ </area>
+ <area condition="{green2}" x="25%" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttongreen" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{green}" />
+ </area>
+ <area condition="{yellow2}" x="25%" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttonyellow" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{yellow}" />
+ </area>
+ <area condition="{blue2}" x="25%" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttonblue" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{blue}" />
+ </area>
+
+ <area condition="{red3}" x="50%" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttonred" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{red}" />
+ </area>
+ <area condition="{green3}" x="50%" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttongreen" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{green}" />
+ </area>
+ <area condition="{yellow3}" x="50%" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttonyellow" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{yellow}" />
+ </area>
+ <area condition="{blue3}" x="50%" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttonblue" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{blue}" />
+ </area>
+
+ <area condition="{red4}" x="75%" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttonred" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{red}" />
+ </area>
+ <area condition="{green4}" x="75%" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttongreen" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{green}" />
+ </area>
+ <area condition="{yellow4}" x="75%" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttonyellow" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{yellow}" />
+ </area>
+ <area condition="{blue4}" x="75%" y="90%" width="25%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="buttonblue" align="center" valign="center" width="90%" height="40%"/>
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{blue}" />
+ </area>
+ </colorbuttons>
+ &displaymenudefault;
+ &displaymenumain;
+ &displaymenusetup;
+ &displaymenuschedules;
+ &displaymenutimers;
+ &displaymenuchannels;
+ &displaymenurecordings;
+ &displaymenudetailepg;
+ &displaymenudetailrecording;
+ &displaymenudetailtext;
+</displaymenu>
diff --git a/skins/nopacity/xmlfiles/displaymenuchannels.xml b/skins/nopacity/xmlfiles/displaymenuchannels.xml
new file mode 100644
index 0000000..9e1512f
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displaymenuchannels.xml
@@ -0,0 +1,127 @@
+<menuchannels x="0" y="0" width="100%" height="100%" fadetime="0" scaletvx="33%" scaletvy="10%" scaletvwidth="65%" scaletvheight="80%">
+ <scrollbar>
+ <area x="30%" y="11%" width="2%" height="78%" layer="2">
+ <fill color="{clrDarkBlue}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrDarkGreen}" />
+ </area>
+ </scrollbar>
+
+ <menuitems x="{areawidth}*0.005" y="10%" orientation="vertical" width="99%" height="80%" align="center" numlistelements="10">
+ <!-- Available Variables channels menu listelement:
+ {number} number of the displayed channel
+ {name} name of the displayed channel
+ {channelid} ChannelID as path to display channel logo
+ {transponder} Transponder of channel
+ {frequency} Frequency of channel
+ {source} Source of channel (S, C, T)
+ {sourcedescription} Descriptin of source from sources.conf
+ {position} orbital position of the satellite in case this is a DVB-S source
+ {isAtsc} true if channel is a ATSC channel
+ {isCable} true if channel is cable channel
+ {isSat} true if channel is a satellite channel
+ {isTerr} true if channel is terrestrical
+ {presenteventtitle} title of present event on this channel
+ {presenteventstart} present event start time in hh::mm
+ {presenteventstop} present event event stop time in hh::mm
+ {current} true if item is currently selected
+ {separator} true if item is a list separator
+ -->
+ <listelement>
+ <!-- background and foreground-->
+ <area x="0" width="28%" layer="2">
+ <drawimage condition="not{current}" imagetype="skinpart" path="menubutton" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ <drawimage condition="{current}" imagetype="skinpart" path="menubuttonactive" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ </area>
+ <!-- channel logo -->
+ <area condition="not{separator}" x="5" width="6%" layer="3">
+ <drawimage name="logo" imagetype="channellogo" path="{channelid}" x="0" height="100%" valign="center" />
+ </area>
+ <!-- scrollable channel name -->
+ <areascroll condition="not{separator}++not{current}" scrollelement="channelname" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="7%" width="20%" layer="3">
+ <drawtext name="channelname" x="0" y="5" font="{vdrOsd}" fontsize="50%" color="{clrFontMenuItem}" text="{number} {name}" />
+ </areascroll>
+ <areascroll condition="not{separator}++{current}" scrollelement="channelname" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="7%" width="20%" layer="3">
+ <drawtext name="channelname" x="0" y="5" font="{vdrOsd}" fontsize="50%" color="{clrFontMenuItemSelected}" text="{number} {name}" />
+ </areascroll>
+ <!-- channel information -->
+ <area condition="not{separator}++not{current}" x="7%" width="20%" layer="3">
+ <drawtext x="0" y="60%" font="{vdrOsd}" fontsize="30%" color="{clrFontMenuItem}" text="{sourcedescription}, {tr(transponder)} {transponder}" />
+ </area>
+ <area condition="not{separator}++{current}" x="7%" width="20%" layer="3">
+ <drawtext x="0" y="60%" font="{vdrOsd}" fontsize="30%" color="{clrFontMenuItemSelected}" text="{sourcedescription}, {tr(transponder)} {transponder}" />
+ </area>
+ <!-- separator -->
+ <area condition="{separator}" x="0" width="28%" layer="3">
+ <drawimage name="sep" imagetype="icon" path="ico_channelsep" x="10" valign="center" width="{areaheight}-10" height="{areaheight}-10"/>
+ <drawtext x="{width(sep)} + 20" valign="center" font="{vdrOsd}" fontsize="60%" color="{clrFontInactive}" text="{name}" />
+ </area>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables channels menu currentelement:
+ {number} number of the displayed channel
+ {name} name of the displayed channel
+ {channelid} ChannelID as path to display channel logo
+ {transponder} Transponder of channel
+ {frequency} Frequency of channel
+ {source} Source of channel (S, C, T)
+ {sourcedescription} Descriptin of source from sources.conf
+ {position} orbital position of the satellite in case this is a DVB-S source
+ {isAtsc} true if channel is a ATSC channel
+ {isCable} true if channel is cable channel
+ {isSat} true if channel is a satellite channel
+ {isTerr} true if channel is terrestrical
+ {presenteventtitle} title of present event on this channel
+ {presenteventstart} present event start time in hh::mm
+ {presenteventstop} present event stop time in hh::mm
+ {presenteventshorttext} present event short text
+ {presenteventdescription} present event description
+ {presenteventday} present event name of day
+ {presenteventdate} present event date in dd:mm:yy
+ {presenteventelapsed} present event elapsed time
+ {presenteventduration} present event duration
+ {hasposter} true if a scraped poster is available for this elements present evemt
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {nexteventtitle} title of next event on this channel
+ {nexteventstart} next event start time in hh::mm
+ {nexteventstop} next event event stop time in hh::mm
+ {nexteventshorttext} next event short text
+ {nexteventdescription} next event description
+ {nexteventday} next event name of day
+ {nexteventdate} next event date in dd:mm:yy
+ {nexteventdate} next event duration
+ {schedule[]} array with following 10 schedules
+ {schedule[title]} title of event
+ {schedule[shorttext]} shorttext of event
+ {schedule[start]} start time of event in hh:mm
+ {schedule[stop]} stop time of event in hh:mm
+ -->
+ <currentelement delay="500" fadetime="300">
+ <area x="32%" y="2%" width="67%" height="96%" layer="2">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <area x="32%" y="2%" width="67%" height="76%" layer="2">
+ <!-- Logo and Header -->
+ <drawimage name="logo" imagetype="channellogo" path="{channelid}" x="1%" y="1%" width="20%" />
+ <drawtext name="channelname" x="23%" y="{height(logo)} * 3 / 10" font="{vdrOsd}" fontsize="10%" color="{clrWhite}" text="{number} - {name}" />
+ <drawtext x="23%" y="{posy(channelname)} + {height(channelname)}" font="{vdrOsd}" fontsize="7%" color="{clrWhite}" text="{sourcedescription}, {tr(transponder)} {transponder}" />
+ <!-- NOW -->
+ <drawtext name="headernow" x="1%" y="{posy(logo)} + {height(logo)} + 10" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{tr(now)}: {presenteventstart} - {presenteventstop}" />
+ <drawtext name="titlenow" x="1%" y="{posy(headernow)} + {height(headernow)}" width="48%" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{presenteventtitle}" />
+ <drawtextbox x="1%" y="{posy(titlenow)} + {height(titlenow)} + 10" width="48%" height="{areaheight} - {posy(titlenow)} - {height(titlenow)} - 10" font="{vdrOsd}" fontsize="5%" color="{clrWhite}" text="{presenteventshorttext}&#10;&#10;{presenteventdescription}" />
+ <!-- NEXT -->
+ <drawtext name="headernext" x="51%" y="{posy(logo)} + {height(logo)} + 10" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{tr(next)}: {nexteventstart} - {nexteventstop}" />
+ <drawtext name="titlenext" x="51%" y="{posy(headernext)} + {height(headernext)}" width="48%" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{nexteventtitle}" />
+ <drawtextbox x="51%" y="{posy(titlenext)} + {height(titlenext)} + 10" width="48%" height="{areaheight} - {posy(titlenext)} - {height(titlenext)} - 10" font="{vdrOsd}" fontsize="5%" color="{clrWhite}" text="{nexteventshorttext}&#10;&#10;{nexteventdescription}" />
+ </area>
+ <areascroll mode="forthandback" orientation="vertical" delay="1000" scrollspeed="medium" x="32%" y="78%" width="67%" height="20%" layer="2">
+ <drawtext x="10" y="0" font="{semibold}" fontsize="20%" color="{clrWhite}" text="{tr(nextschedules)}:" />
+ <loop name="schedule" x="0" y="{areaheight}/4 + 5" orientation="vertical">
+ <drawtext x="10" font="{vdrOsd}" width="{areawidth}-20" fontsize="19%" color="{clrWhite}" text="{schedule[start]} {schedule[title]}" />
+ </loop>
+ </areascroll>
+ </currentelement>
+ </menuitems>
+</menuchannels> \ No newline at end of file
diff --git a/skins/nopacity/xmlfiles/displaymenudefault.xml b/skins/nopacity/xmlfiles/displaymenudefault.xml
new file mode 100644
index 0000000..2c51339
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displaymenudefault.xml
@@ -0,0 +1,65 @@
+ <menudefault x="0" y="0" width="100%" height="100%" fadetime="0" scaletvx="0" scaletvy="0" scaletvwidth="0" scaletvheight="0">
+ <background>
+ <area x="0" y="0" width="100%" height="100%" layer="1">
+ <fill color="{clrDarkBlue}" />
+ </area>
+ <area x="0" y="0" width="100%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="headertop" x="0" y="0" width="100%" height="100%"/>
+ </area>
+ </background>
+
+ <!-- IMPORTANT: menuitemwidth and determinatefont have to be defined here. menuitemwidth defines the total width of the
+ default menu items, determinatefont the function which sets the actual font to use. With that it is possible to determinate
+ the correct column widths -->
+ <menuitems x="1%" y="10%" orientation="vertical" width="96%" height="80%" align="center" menuitemwidth="96%" determinatefont="column1" numlistelements="16">
+ <!-- Available Variables default menu listelement:
+ {column1} text of column1
+ {column2} text of column2
+ {column3} text of column3
+ {column4} text of column4
+ {column5} text of column5
+ {column6} text of column6
+ {column2set} true if column2 is used
+ {column3set} true if column3 is used
+ {column4set} true if column4 is used
+ {column5set} true if column5 is used
+ {column6set} true if column6 is used
+ {column2x} proposed x value of column2
+ {column3x} proposed x value of column3
+ {column4x} proposed x value of column4
+ {column5x} proposed x value of column5
+ {column6x} proposed x value of column6
+ {column1width} proposed width of column1
+ {column2width} proposed width of column2
+ {column3width} proposed width of column3
+ {column4width} proposed width of column4
+ {column5width} proposed width of column5
+ {column6width} proposed width of column6
+ {current} true if column is currently selected
+ {separator} true if column is a list separator
+ -->
+ <listelement>
+ <area x="0" width="100%" layer="2">
+ <drawimage condition="not{current}" imagetype="skinpart" path="menubuttondefault" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ <drawimage condition="{current}" imagetype="skinpart" path="menubuttondefaultactive" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ </area>
+ <areascroll scrollelement="column1" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="1%" width="{column1width}" layer="3">
+ <drawtext condition="not{current}" name="column1" x="{column1x}" width="{column1width}" valign="center" font="{vdrOsd}" fontsize="90%" color="{clrFontMenuItem}" text="{column1}" />
+ <drawtext condition="{current}" name="column1" x="{column1x}" width="{column1width}" valign="center" font="{vdrOsd}" fontsize="90%" color="{clrFontMenuItemSelected}" text="{column1}" />
+ </areascroll>
+ <area x="1%" width="100%" layer="3">
+ <drawtext condition="{column2set}++not{current}" x="{column2x}" valign="center" width="{column2width}" font="{vdrOsd}" fontsize="90%" color="{clrFontMenuItem}" text="{column2}" />
+ <drawtext condition="{column2set}++{current}" x="{column2x}" valign="center" width="{column2width}" font="{vdrOsd}" fontsize="90%" color="{clrFontMenuItemSelected}" text="{column2}" />
+ <drawtext condition="{column3set}++not{current}" x="{column3x}" valign="center" width="{column3width}" font="{vdrOsd}" fontsize="90%" color="{clrFontMenuItem}" text="{column3}" />
+ <drawtext condition="{column3set}++{current}" x="{column3x}" valign="center" width="{column3width}" font="{vdrOsd}" fontsize="90%" color="{clrFontMenuItemSelected}" text="{column3}" />
+ <drawtext condition="{column4set}++not{current}" x="{column4x}" valign="center" width="{column4width}" font="{vdrOsd}" fontsize="90%" color="{clrFontMenuItem}" text="{column4}" />
+ <drawtext condition="{column4set}++{current}" x="{column4x}" valign="center" width="{column4width}" font="{vdrOsd}" fontsize="90%" color="{clrFontMenuItemSelected}" text="{column4}" />
+ <drawtext condition="{column5set}++not{current}" x="{column5x}" valign="center" width="{column5width}" font="{vdrOsd}" fontsize="90%" color="{clrFontMenuItem}" text="{column5}" />
+ <drawtext condition="{column5set}++{current}" x="{column5x}" valign="center" width="{column5width}" font="{vdrOsd}" fontsize="90%" color="{clrFontMenuItemSelected}" text="{column5}" />
+ <drawtext condition="{column6set}++not{current}" x="{column6x}" valign="center" width="{column6width}" font="{vdrOsd}" fontsize="90%" color="{clrFontMenuItem}" text="{column6}" />
+ <drawtext condition="{column6set}++{current}" x="{column6x}" valign="center" width="{column6width}" font="{vdrOsd}" fontsize="90%" color="{clrFontMenuItemSelected}" text="{column6}" />
+ </area>
+ </listelement>
+
+ </menuitems>
+</menudefault>
diff --git a/skins/nopacity/xmlfiles/displaymenudetailepg.xml b/skins/nopacity/xmlfiles/displaymenudetailepg.xml
new file mode 100644
index 0000000..3635ec8
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displaymenudetailepg.xml
@@ -0,0 +1,256 @@
+<menudetailedepg x="0" y="0" width="100%" height="100%" fadetime="0">
+ <background>
+ <area x="0" y="0" width="100%" height="100%" layer="1">
+ <fill color="{clrTransBlack}" />
+ <drawrectangle x="0" y="0" width="100%" height="10%" color="{clrDarkBlue}" />
+ </area>
+ <area x="0" y="0" width="100%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="headertop" x="0" y="0" width="100%" height="100%"/>
+ </area>
+ </background>
+ <scrollbar>
+ <area x="97%" y="25%" width="2%" height="60%" layer="2">
+ <fill color="{clrDarkBlue}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrDarkGreen}" />
+ </area>
+ </scrollbar>
+ <!-- Available Variables in detailheader elements:
+ {title} title of event
+ {shorttext} shorttext of event
+ {start} event start time in hh::mm
+ {stop} event stop time
+ {day} day of current event
+ {date} date of current event in dd.mm.yy
+ {running} true if event is currently running
+ {elapsed} elapsed time of event, if not running 0
+ {duration} duration of event
+ {channelid} ChannelID as path to display channel logo
+ {ismovie} true if event is scraped as a movie
+ {isseries} true if event is scraped as a series
+ {posteravailable} true if a poster is available
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {banneravailable} true if a banner is available
+ {bannerwidth} width of banner
+ {bannerheight} height of banner
+ {bannerpath} path of banner
+ {epgpicavailable} true if a epg picture is available
+ {epgpicpath} path of epg picture
+ -->
+ <detailheader>
+ <area x="1%" y="10%" width="98%" height="15%" layer="2">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <area x="1%" y="10%" width="98%" height="15%" layer="3">
+ <drawimage name="logo" imagetype="channellogo" path="{channelid}" x="0" height="80%" valign="center" />
+
+ <drawimage condition="{isseries}++{banneravailable}++not{epgpicavailable}" imagetype="image" path="{bannerpath}" x="{areawidth} - {areawidth}/3 - 10" valign="center" width="{areawidth}/3" height="{areawidth}/3 * {bannerheight} / {bannerwidth}"/>
+ <drawimage condition="{ismovie}++{posteravailable}++not{epgpicavailable}" imagetype="image" path="{posterpath}" x="{areawidth} - {areaheight}*8/10" valign="center" width="{areaheight}*8 / 10 * {posterheight} / {posterwidth}" height="{areaheight}*8 / 10"/>
+ <drawimage condition="{epgpicavailable}" imagetype="image" path="{epgpicpath}" x="{areawidth} - {areaheight}*8/10 * 174 / 130" valign="center" width="{areaheight}*8/10 * 174 / 130" height="{areaheight}*8 / 10"/>
+
+ <drawtext name="title" x="{width(logo)} + 20" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{title}" />
+ <drawtext name="datetime" x="{width(logo)} + 20" y="{posy(title)} - {height(datetime)}" font="{vdrOsd}" fontsize="25%" color="{clrWhite}" text="{day} {date} {start} - {stop} ({duration} mins)" />
+ <drawtext name="shorttext" x="{width(logo)} + 20" y="{posy(title)} + {height(title)}" font="{vdrOsd}" fontsize="25%" color="{clrWhite}" text="{shorttext}" />
+ </area>
+ </detailheader>
+
+ <!-- Available Variables in tab elements:
+ {title} title of event
+ {shorttext} shorttext of event
+ {description} description of event
+ {start} event start time in hh::mm
+ {stop} event stop time
+ {day} day of current event
+ {date} date of current event in dd.mm.yy
+ {running} true if event is currently running
+ {elapsed} elapsed time of event, if not running 0
+ {duration} duration of event
+ {channelid} ChannelID as path to display channel logo
+ {hasreruns} true if reruns of this event are found
+ {reruns[]} array with reruns
+ {reruns[title]} title of rerun
+ {reruns[shorttext]} shorttext of rerun
+ {reruns[date]} date of rerun in dd:mm
+ {reruns[day]} short dayname of rerun
+ {reruns[start]} start time of rerun in hh:mm
+ {reruns[stop]} stop time of rerun in hh:mm
+ {reruns[channelname]} name of channel on which rerun occurs
+ {reruns[channelnumber]} number of channel on which rerun occurs
+ {reruns[channelid]} id of channel on which rerun occurs to display channel logo
+ {reruns[channellogoexists]} true if channel logo exists
+ {epgpic1avaialble} true if first epg picture is available
+ {epgpic2avaialble} true if first epg picture is available
+ {epgpic3avaialble} true if first epg picture is available
+ {epgpic1path} path of first epg picture
+ {epgpic2path} path of second epg picture
+ {epgpic3path} path of third epg picture
+
+ {ismovie} true if event is scraped as a movie
+ Available variables for movies:
+ {movietitle} movie title from themoviedb
+ {movieoriginalTitle} movie original title from themoviedb
+ {movietagline} movie tagline from themoviedb
+ {movieoverview} movie overview from themoviedb
+ {movieadult} true if movie is rated as adult
+ {moviebudget} movie budget from themoviedb in $
+ {movierevenue} movie revenue from themoviedb in $
+ {moviegenres} movie genres from themoviedb
+ {moviehomepage} movie homepage from themoviedb
+ {moviereleasedate} movie release date from themoviedb
+ {movieruntime} movie runtime from themoviedb
+ {moviepopularity} movie popularity from themoviedb
+ {movievoteaverage} movie vote average from themoviedb
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {fanartwidth} width of scraped fanart
+ {fanartheight} height of scraped fanart
+ {fanartpath} absolute path of scraped fanart
+ {movieiscollection} true if movie is part of a collection
+ {moviecollectionName} name of movie collection
+ {collectionposterwidth} width of scraped collection poster
+ {collectionposterheight} height of scraped collection poster
+ {collectionposterpath} absolute path of scraped collection poster
+ {collectionfanartwidth} width of scraped collection fanart
+ {collectionfanartheight} height of scraped collection fanart
+ {collectionfanartpath} absolute path of scraped collection fanart
+ {actors[]} array with movie actors
+ {actors[name]} real name of actor
+ {actors[role]} actor role
+ {actors[thumb]} absolute path of scraped actor thumb
+ {actors[thumbwidth]} width of scraped actor thumb
+ {actors[thumbheight]} height of scraped actor thumb
+
+ {isseries} true if event is scraped as a series
+ Available variables for series:
+ {seriesname} name of series
+ {seriesoverview} series overview
+ {seriesfirstaired} first aired date
+ {seriesnetwork} network which produces series
+ {seriesgenre} series genre
+ {seriesrating} series thetvdb rating
+ {seriesstatus} status of series (running / finished)
+ {episodetitle} title of episode
+ {episodenumber} number of episode
+ {episodeseason} season of episode
+ {episodefirstaired} first aired date of episode
+ {episodegueststars} guest stars of episode
+ {episodeoverview} episode overview
+ {episoderating} user rating for episode
+ {episodeimagewidth} episode image width
+ {episodeimageheight} episode image height
+ {episodeimagepath} episode image path
+ {seasonposterwidth} episode season poster width
+ {seasonposterheight} episode season poster height
+ {seasonposterpath} episode season poster path
+ {seriesposter1width} width of 1st poster
+ {seriesposter1height} height of 1st poster
+ {seriesposter1path} path of 1st poster
+ {seriesposter2width} width of 2nd poster
+ {seriesposter2height} height of 2nd poster
+ {seriesposter2path} path of 2nd poster
+ {seriesposter3width} width of 3rd poster
+ {seriesposter3height} height of 3rd poster
+ {seriesposter3path} path of 3rd poster
+ {seriesfanart1width} width of 1st fanart
+ {seriesfanart1height} height of 1st fanart
+ {seriesfanart1path} path of 1st fanart
+ {seriesfanart2width} width of 2nd fanart
+ {seriesfanart2height} height of 2nd fanart
+ {seriesfanart2path} path of 2nd fanart
+ {seriesfanart3width} width of 3rd fanart
+ {seriesfanart3height} height of 3rd fanart
+ {seriesfanart3path} path of 3rd fanart
+ {seriesbanner1width} width of 1st banner
+ {seriesbanner1height} height of 1st banner
+ {seriesbanner1path} path of 1st banner
+ {seriesbanner2width} width of 2nd banner
+ {seriesbanner2height} height of 2nd banner
+ {seriesbanner2path} path of 2nd banner
+ {seriesbanner3width} width of 3rd banner
+ {seriesbanner3height} height of 3rd banner
+ {seriesbanner3path} path of 3rd fanart
+ {actors[]} array with movie actors
+ {actors[name]} real name of actor
+ {actors[role]} actor role
+ {actors[thumb]} absolute path of scraped actor thumb
+ {actors[thumbwidth]} width of scraped actor thumb
+ {actors[thumbheight]} height of scraped actor thumb
+ -->
+
+ <!-- TAB EPGINFO -->
+ <tab name="EPG Info" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawtextbox condition="not{isseries}++not{ismovie}" x="0" y="10" width="96%" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{description}" />
+ <drawimage condition="{isseries}" name="seriesposter" imagetype="image" path="{seriesposter1path}" x="{areawidth}*0.75" y="10" width="{areawidth}*0.25" height="{areawidth} * 0.25 * {seriesposter1height} / {seriesposter1width}"/>
+ <drawimage condition="{ismovie}" name="movieposter" imagetype="image" path="{posterpath}" x="{areawidth}*0.75" y="10" width="{areawidth}*0.25" height="{areawidth} * 0.25 * {posterheight} / {posterwidth}" />
+ <drawtextbox condition="{isseries}" x="0" y="10" width="96%" float="topright" floatwidth="{width(seriesposter)} + 10" floatheight="{height(seriesposter)} + 20" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{description}" />
+ <drawtextbox condition="{ismovie}" x="0" y="10" width="96%" float="topright" floatwidth="{width(movieposter)} + 10" floatheight="{height(movieposter)} + 20" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{description}" />
+ </tab>
+ <!-- TAB RERUNS -->
+ <tab condition="{hasreruns}" name="{tr(reruns)}" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawtext align="center" y="0" name="title" font="{vdrOsd}" fontsize="10%" color="{clrWhite}" text="{tr(rerunsof)} '{title}'" />
+ <loop name="reruns" x="0" y="{height(title)} + 10" width="{areawidth}" orientation="vertical">
+ <drawimage name="logo" condition="{reruns[channellogoexists]}" imagetype="channellogo" path="{reruns[channelid]}" x="0" height="10%" />
+ <drawtext name="channelname" condition="not{reruns[channellogoexists]}" x="-5" font="{vdrOsd}" fontsize="10%" color="{clrWhite}" text="{reruns[channelname]}" />
+ <drawtext condition="{reruns[channellogoexists]}" x="{width(logo)}+20" y="-5" width="{areawidth} - {width(logo)} - 20" font="{vdrOsd}" fontsize="8%" color="{clrWhite}" text="{reruns[day]} {reruns[date]} {reruns[start]} - {reruns[stop]}: {reruns[title]} {reruns[shorttext]}" />
+ <drawtext condition="not{reruns[channellogoexists]}" x="{width(channelname)}+20" y="-5" width="{areawidth} - {width(logo)} - 20" font="{vdrOsd}" fontsize="8%" color="{clrWhite}" text="{reruns[day]} {reruns[date]} {reruns[start]} - {reruns[stop]}: {reruns[title]} {reruns[shorttext]}" />
+ </loop>
+ </tab>
+ <!-- TAB ACTORS -->
+ <tab condition="{isseries}||{ismovie}" name="{tr(actors)}" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawtext align="center" name="title" y="0" font="{vdrOsd}" fontsize="15%" color="{clrWhite}" text="{tr(actors)}" />
+ <loop name="actors" x="0" y="{height(title)} + 10" width="{areawidth}" orientation="horizontal" columnwidth="{areawidth}/5" rowheight="{areawidth}/5*1.8" overflow="linewrap">
+ <drawimage name="thumb" imagetype="image" path="{actors[thumb]}" x="20" y="0" width="{columnwidth}-40" height="{columnwidth} * {actors[thumbheight]} / {actors[thumbwidth]} - 40 * {actors[thumbheight]} / {actors[thumbwidth]}"/>
+ <drawtext align="center" y="{height(thumb)} + 10" width="{columnwidth}" name="actorname" font="{vdrOsd}" fontsize="7%" color="{clrWhite}" text="{actors[name]}" />
+ <drawtext align="center" y="{height(thumb)} + 10 + {height(actorname)}" width="{columnwidth}" font="{vdrOsd}" fontsize="7%" color="{clrWhite}" text="{actors[role]}" />
+ </loop>
+ </tab>
+ <!-- TAB TVDBINFO -->
+ <tab condition="{isseries}" name="TvDBInfo" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="banner" imagetype="image" path="{seriesbanner1path}" align="center" y="10" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner1height} / {seriesbanner1width}"/>
+ <drawimage name="episodeimage" imagetype="image" path="{episodeimagepath}" x="{areawidth}*0.7" y="{height(banner)} + 20" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {episodeimageheight} / {episodeimagewidth}"/>
+ <drawimage name="seasonposter" imagetype="image" path="{seasonposterpath}" x="{areawidth}*0.7" y="{height(banner)} + {height(episodeimage)} + 30" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {seasonposterheight} / {seasonposterwidth}"/>
+ <drawtextbox x="0" y="{height(banner)} + 20" width="96%" float="topright" floatwidth="{width(seasonposter)} + 10" floatheight="{height(episodeimage)} + {height(seasonposter)} + 30" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{tr(episode)}: {episodetitle} ({tr(season)} {episodeseason}, {tr(episode)} {episodenumber}) &#10;&#10;{episodeoverview}|&#10;&#10;{tr(gueststars)}: {episodegueststars}||&#10;&#10;{tr(seriesfirstaired)}: {seriesfirstaired}||&#10;{tr(episodefirstaired)}: {episodefirstaired}||&#10;{tr(network)}: {seriesnetwork}||&#10;{tr(genre)}: {seriesgenre}||&#10;{tr(status)}: {seriesstatus}||&#10;{tr(rating)}: {seriesrating}||&#10;{tr(episoderating)}: {episoderating}&#10;|{seriesoverview}&#10;" />
+ </tab>
+ <!-- TAB SERIESGALERY -->
+ <tab condition="{isseries}" name="{tr(seriesgalery)}" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="banner1" imagetype="image" path="{seriesbanner1path}" align="center" y="10" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner1height} / {seriesbanner1width}"/>
+ <drawimage name="fanart1" imagetype="image" path="{seriesfanart1path}" align="center" y="{posy(banner1)} + {height(banner1)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesfanart1height} / {seriesfanart1width}"/>
+ <drawimage name="banner2" imagetype="image" path="{seriesbanner2path}" align="center" y="{posy(fanart1)} + {height(fanart1)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner2height} / {seriesbanner2width}"/>
+ <drawimage name="fanart2" imagetype="image" path="{seriesfanart2path}" align="center" y="{posy(banner2)} + {height(banner2)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesfanart2height} / {seriesfanart2width}"/>
+ <drawimage name="banner3" imagetype="image" path="{seriesbanner3path}" align="center" y="{posy(fanart2)} + {height(fanart2)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner3height} / {seriesbanner3width}"/>
+ <drawimage name="fanart3" imagetype="image" path="{seriesfanart3path}" align="center" y="{posy(banner3)} + {height(banner3)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesfanart3height} / {seriesfanart3width}"/>
+ <drawimage name="poster1" imagetype="image" path="{seriesposter1path}" align="center" y="{posy(fanart3)} + {height(fanart3)} + 20" width="{areawidth}*0.5" height="{areawidth} * 0.5 * {seriesposter1height} / {seriesposter1width}"/>
+ <drawimage name="poster2" imagetype="image" path="{seriesposter2path}" align="center" y="{posy(poster1)} + {height(poster1)} + 20" width="{areawidth}*0.5" height="{areawidth} * 0.5 * {seriesposter2height} / {seriesposter2width}"/>
+ <drawimage name="poster3" imagetype="image" path="{seriesposter3path}" align="center" y="{posy(poster2)} + {height(poster2)} + 20" width="{areawidth}*0.5" height="{areawidth} * 0.5 * {seriesposter3height} / {seriesposter3width}"/>
+ </tab>
+ <!-- TAB MOVIEDBINFO -->
+ <tab condition="{ismovie}" name="MovieDBInfo" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="poster" imagetype="image" path="{posterpath}" x="70%" y="10" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {posterheight} / {posterwidth}"/>
+ <drawtextbox x="0" y="10" width="96%" float="topright" floatwidth="{width(poster)} + 10" floatheight="{height(poster)} + 20" font="{vdrOsd}" fontsize="8%" color="{clrWhite}" text="{tr(originaltitle)}: {movieoriginalTitle}&#10;&#10;|{tr(genre)}: {moviegenres}&#10;&#10;||{movietagline}&#10;&#10;|{movieoverview}&#10;&#10;|{tr(budget)}: {moviebudget}&#10;||{tr(revenue)}: {movierevenue}&#10;&#10;||{tr(adult)}: {movieadult}&#10;||{tr(releasedate)}: {moviereleasedate}&#10;||{tr(runtime)}: {movieruntime} min&#10;||&#10;{tr(popularity)}: {moviepopularity}&#10;||&#10;{tr(voteaverage)}: {movievoteaverage}&#10;||&#10;{tr(homepage)}: {moviehomepage}|&#10;" />
+ </tab>
+ <!-- TAB MOVIEGALERY -->
+ <tab condition="{ismovie}" name="{tr(moviegalery)}" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="fanart" imagetype="image" path="{fanartpath}" align="center" y="10" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {fanartheight} / {fanartwidth}"/>
+ <drawimage name="poster" imagetype="image" path="{posterpath}" align="center" y="{height(fanart)} + 30" width="{areawidth}*0.6" height="{areawidth} * 0.6 * {posterheight} / {posterwidth}"/>
+ <drawimage condition="{movieiscollection}" name="collectionfanart" imagetype="image" path="{collectionfanartpath}" align="center" y="{posy(poster)} + {height(poster)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {collectionfanartheight} / {collectionfanartwidth}"/>
+ <drawimage condition="{movieiscollection}" name="collectionposter" imagetype="image" path="{collectionposterpath}" align="center" y="{posy(collectionfanart)} + {height(collectionfanart)} + 20" width="{areawidth}*0.6" height="{areawidth} * 0.6 * {collectionposterheight} / {collectionposterwidth}"/>
+ </tab>
+ <!-- Available Variables tablabels:
+ {tabs[]} array with available tab labels
+ {tabs[title]} title of tab
+ {tabs[current]} true if tab is displayed currently
+ -->
+ <tablabels>
+ <area x="1%" y="85%" width="98%" height="5%" layer="3">
+ <loop name="tabs" x="0" y="0" orientation="horizontal">
+ <drawrectangle condition="{tabs[current]}" x="0" y="0" width="{width(label)}" height="100%" color="{clrDarkGreen}" />
+ <drawrectangle condition="not{tabs[current]}" x="0" y="0" width="{width(label)}" height="100%" color="{clrDarkGreen}" />
+ <drawrectangle condition="not{tabs[current]}" x="2" y="2" width="{width(label)} - 4" height="{areaheight}-4" color="{clrTransparent}" />
+ <drawtext name="label" x="0" valign="center" font="{vdrOsd}" fontsize="95%" color="{clrWhite}" text=" {tabs[title]} " />
+ </loop>
+ </area>
+ </tablabels>
+</menudetailedepg> \ No newline at end of file
diff --git a/skins/nopacity/xmlfiles/displaymenudetailrecording.xml b/skins/nopacity/xmlfiles/displaymenudetailrecording.xml
new file mode 100644
index 0000000..07df0fd
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displaymenudetailrecording.xml
@@ -0,0 +1,233 @@
+<menudetailedrecording x="0" y="0" width="100%" height="100%" fadetime="0">
+ <background>
+ <area x="0" y="0" width="100%" height="100%" layer="1">
+ <fill color="{clrTransBlack}" />
+ <drawrectangle x="0" y="0" width="100%" height="10%" color="{clrDarkBlue}" />
+ </area>
+ <area x="0" y="0" width="100%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="headertop" x="0" y="0" width="100%" height="100%"/>
+ </area>
+ </background>
+ <scrollbar>
+ <area x="97%" y="25%" width="2%" height="60%" layer="2">
+ <fill color="{clrDarkBlue}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrDarkGreen}" />
+ </area>
+ </scrollbar>
+ <!-- Available Variables in detailheader elements:
+ {name} name of recording
+ {shorttext} shorttext of recording
+ {date} date of recording in dd.mm.yy
+ {time} time of current event in hh:mm
+ {duration} real duration of recording in minutes
+ {durationevent} duration of according event in minutes
+ {ismovie} true if event is scraped as a movie
+ {isseries} true if event is scraped as a series
+ {posteravailable} true if a poster is available
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {banneravailable} true if a banner is available
+ {bannerwidth} width of banner
+ {bannerheight} height of banner
+ {bannerpath} path of banner
+ {recimgavailable} true if a recording image is available in the recording path
+ {recimgpath} path of rec image
+ -->
+ <detailheader>
+ <area x="1%" y="10%" width="98%" height="15%" layer="2">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <area x="1%" y="10%" width="98%" height="15%" layer="3">
+ <drawimage condition="{isseries}++{banneravailable}++not{recimgavailable}" imagetype="image" path="{bannerpath}" x="{areawidth} - {areawidth}/3 - 10" valign="center" width="{areawidth}/3" height="{areawidth}/3 * {bannerheight} / {bannerwidth}"/>
+ <drawimage condition="{ismovie}++{posteravailable}++not{recimgavailable}" imagetype="image" path="{posterpath}" x="{areawidth} - {areaheight}*8/10" valign="center" width="{areaheight}*8 / 10 * {posterheight} / {posterwidth}" height="{areaheight}*8 / 10"/>
+ <drawimage condition="{recimgavailable}" imagetype="image" path="{recimgpath}" x="{areawidth} - {areaheight}*8/10 * 174 / 130" valign="center" width="{areaheight}*8/10 * 174 / 130" height="{areaheight}*8 / 10"/>
+ <drawtext name="title" x="20" valign="center" font="{vdrOsd}" fontsize="35%" color="{clrWhite}" text="{name}" />
+ <drawtext name="datetime" x="20" y="{posy(title)} - {height(datetime)}" font="{vdrOsd}" fontsize="25%" color="{clrWhite}" text="{date} {time} ({duration} mins)" />
+ <drawtext name="shorttext" x="20" y="{posy(title)} + {height(title)}" font="{vdrOsd}" fontsize="25%" color="{clrWhite}" text="{shorttext}" />
+ </area>
+ </detailheader>
+ <!-- Available Variables in tab elements:
+ {name} title of recording
+ {shorttext} shorttext of recording
+ {description} description of recording
+ {date} date of recording in dd.mm.yy
+ {time} time of recording in hh:mm
+ {duration} real duration of recording in minutes
+ {durationevent} duration of according event in minutes
+
+ {recordingsize} size of recording (automatically in GB / MB)
+ {recordingsizecutted} size of cutted recording (automatically in GB / MB)
+ {recordinglength} length of recording (in hh::mm:ss)
+ {recordinglengthcutted} length of cutted recording (in hh::mm:ss)
+ {recordingbitrate} bitrate of recording (in MBit/s)
+ {recordingformat} format of recording (TS / PS)
+ {searchtimer} name of accordign searchtimer (if available)
+
+ {recimg1avaialble} true if first recording image is available
+ {recimg2avaialble} true if first recording image is available
+ {recimg3avaialble} true if first recording image is available
+ {recimg1path} path of first recording image
+ {recimg2path} path of second recording image
+ {recimg3path} path of third recording image
+
+ {ismovie} true if event is scraped as a movie
+ Available variables for movies:
+ {movietitle} movie title from themoviedb
+ {movieoriginalTitle} movie original title from themoviedb
+ {movietagline} movie tagline from themoviedb
+ {movieoverview} movie overview from themoviedb
+ {movieadult} true if movie is rated as adult
+ {moviebudget} movie budget from themoviedb in $
+ {movierevenue} movie revenue from themoviedb in $
+ {moviegenres} movie genres from themoviedb
+ {moviehomepage} movie homepage from themoviedb
+ {moviereleasedate} movie release date from themoviedb
+ {movieruntime} movie runtime from themoviedb
+ {moviepopularity} movie popularity from themoviedb
+ {movievoteaverage} movie vote average from themoviedb
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {fanartwidth} width of scraped fanart
+ {fanartheight} height of scraped fanart
+ {fanartpath} absolute path of scraped fanart
+ {movieiscollection} true if movie is part of a collection
+ {moviecollectionName} name of movie collection
+ {collectionposterwidth} width of scraped collection poster
+ {collectionposterheight} height of scraped collection poster
+ {collectionposterpath} absolute path of scraped collection poster
+ {collectionfanartwidth} width of scraped collection fanart
+ {collectionfanartheight} height of scraped collection fanart
+ {collectionfanartpath} absolute path of scraped collection fanart
+ {actors[]} array with movie actors
+ {actors[name]} real name of actor
+ {actors[role]} actor role
+ {actors[thumb]} absolute path of scraped actor thumb
+ {actors[thumbwidth]} width of scraped actor thumb
+ {actors[thumbheight]} height of scraped actor thumb
+
+ {isseries} true if event is scraped as a series
+ Available variables for series:
+ {seriesname} name of series
+ {seriesoverview} series overview
+ {seriesfirstaired} first aired date
+ {seriesnetwork} network which produces series
+ {seriesgenre} series genre
+ {seriesrating} series thetvdb rating
+ {seriesstatus} status of series (running / finished)
+ {episodetitle} title of episode
+ {episodenumber} number of episode
+ {episodeseason} season of episode
+ {episodefirstaired} first aired date of episode
+ {episodegueststars} guest stars of episode
+ {episodeoverview} episode overview
+ {episoderating} user rating for episode
+ {episodeimagewidth} episode image width
+ {episodeimageheight} episode image height
+ {episodeimagepath} episode image path
+ {seasonposterwidth} episode season poster width
+ {seasonposterheight} episode season poster height
+ {seasonposterpath} episode season poster path
+ {seriesposter1width} width of 1st poster
+ {seriesposter1height} height of 1st poster
+ {seriesposter1path} path of 1st poster
+ {seriesposter2width} width of 2nd poster
+ {seriesposter2height} height of 2nd poster
+ {seriesposter2path} path of 2nd poster
+ {seriesposter3width} width of 3rd poster
+ {seriesposter3height} height of 3rd poster
+ {seriesposter3path} path of 3rd poster
+ {seriesfanart1width} width of 1st fanart
+ {seriesfanart1height} height of 1st fanart
+ {seriesfanart1path} path of 1st fanart
+ {seriesfanart2width} width of 2nd fanart
+ {seriesfanart2height} height of 2nd fanart
+ {seriesfanart2path} path of 2nd fanart
+ {seriesfanart3width} width of 3rd fanart
+ {seriesfanart3height} height of 3rd fanart
+ {seriesfanart3path} path of 3rd fanart
+ {seriesbanner1width} width of 1st banner
+ {seriesbanner1height} height of 1st banner
+ {seriesbanner1path} path of 1st banner
+ {seriesbanner2width} width of 2nd banner
+ {seriesbanner2height} height of 2nd banner
+ {seriesbanner2path} path of 2nd banner
+ {seriesbanner3width} width of 3rd banner
+ {seriesbanner3height} height of 3rd banner
+ {seriesbanner3path} path of 3rd fanart
+ {actors[]} array with movie actors
+ {actors[name]} real name of actor
+ {actors[role]} actor role
+ {actors[thumb]} absolute path of scraped actor thumb
+ {actors[thumbwidth]} width of scraped actor thumb
+ {actors[thumbheight]} height of scraped actor thumb
+ -->
+
+ <!-- a tab is one scrolling area, just position and draw as inside a normal area -->
+ <!-- just define as many tabs as needed -->
+ <tab name="Info" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawtextbox condition="not{isseries}++not{ismovie}" x="0" y="0" width="96%" font="{vdrOsd}" fontsize="8%" color="{clrWhite}" text="{description}" />
+ <drawimage condition="{isseries}" name="seriesposter" imagetype="image" path="{seriesposter1path}" x="{areawidth}*0.7" y="0" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {seriesposter1height} / {seriesposter1width}"/>
+ <drawimage condition="{ismovie}" name="movieposter" imagetype="image" path="{posterpath}" x="{areawidth}*0.7" y="0" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {posterheight} / {posterwidth}" />
+ <drawtextbox condition="{isseries}" x="0" y="0" width="96%" float="topright" floatwidth="{width(seriesposter)} + 10" floatheight="{height(seriesposter)} + 20" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{description}" />
+ <drawtextbox condition="{ismovie}" x="0" y="0" width="96%" float="topright" floatwidth="{width(movieposter)} + 10" floatheight="{height(movieposter)} + 20" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{description}" />
+ </tab>
+ <tab name="{tr(recinfo)}" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawtext align="center" y="0" name="title" font="{vdrOsd}" fontsize="10%" color="{clrWhite}" text="{tr(recinfo)}" />
+ <drawtextbox x="0" y="{height(title)} + 20" width="96%" font="{vdrOsd}" fontsize="8%" color="{clrWhite}" text="{tr(recsize)}: {recordingsize}&#10;{tr(recsizecutted)}: {recordingsizecutted}&#10;{tr(reclength)}: {recordinglength}&#10;{tr(reclengthcutted)}: {recordinglengthcutted}&#10;{tr(bitrate)}: {recordingbitrate}&#10;{tr(format)}: {recordingformat}&#10;{tr(searchtimer)}: {searchtimer}&#10;" />
+ </tab>
+ <tab condition="{isseries}||{ismovie}" name="{tr(actors)}" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawtext align="center" name="title" y="0" font="{vdrOsd}" fontsize="10%" color="{clrWhite}" text="{tr(actors)}" />
+ <loop name="actors" x="0" y="{height(title)} + 10" width="{areawidth}" orientation="horizontal" columnwidth="{areawidth}/5" rowheight="{areawidth}/5*1.8" overflow="linewrap">
+ <drawimage name="thumb" imagetype="image" path="{actors[thumb]}" x="20" y="0" width="{columnwidth}-40" height="{columnwidth} * {actors[thumbheight]} / {actors[thumbwidth]} - 40 * {actors[thumbheight]} / {actors[thumbwidth]}"/>
+ <drawtext align="center" y="{height(thumb)} + 10" width="{columnwidth}" name="actorname" font="{vdrOsd}" fontsize="7%" color="{clrWhite}" text="{actors[name]}" />
+ <drawtext align="center" y="{height(thumb)} + 10 + {height(actorname)}" width="{columnwidth}" font="{vdrOsd}" fontsize="7%" color="{clrWhite}" text="{actors[role]}" />
+ </loop>
+ </tab>
+ <tab condition="{isseries}" name="TvDBInfo" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="banner" imagetype="image" path="{seriesbanner1path}" align="center" y="10" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner1height} / {seriesbanner1width}"/>
+ <drawimage name="episodeimage" imagetype="image" path="{episodeimagepath}" x="{areawidth}*0.7" y="{height(banner)} + 20" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {episodeimageheight} / {episodeimagewidth}"/>
+ <drawimage name="seasonposter" imagetype="image" path="{seasonposterpath}" x="{areawidth}*0.7" y="{height(banner)} + {height(episodeimage)} + 30" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {seasonposterheight} / {seasonposterwidth}"/>
+ <drawtextbox x="0" y="{height(banner)} + 20" width="96%" float="topright" floatwidth="{width(seasonposter)} + 10" floatheight="{height(episodeimage)} + {height(seasonposter)} + 30" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{tr(episode)}: {episodetitle} ({tr(season)} {episodeseason}, {tr(episode)} {episodenumber}) &#10;&#10;{episodeoverview}|&#10;&#10;{tr(gueststars)}: {episodegueststars}||&#10;&#10;{tr(seriesfirstaired)}: {seriesfirstaired}||&#10;{tr(episodefirstaired)}: {episodefirstaired}||&#10;{tr(network)}: {seriesnetwork}||&#10;{tr(genre)}: {seriesgenre}||&#10;{tr(status)}: {seriesstatus}||&#10;{tr(rating)}: {seriesrating}||&#10;{tr(episoderating)}: {episoderating}&#10;|{seriesoverview}&#10;" />
+ </tab>
+ <tab condition="{isseries}" name="{tr(seriesgalery)}" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="banner1" imagetype="image" path="{seriesbanner1path}" align="center" y="10" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner1height} / {seriesbanner1width}"/>
+ <drawimage name="fanart1" imagetype="image" path="{seriesfanart1path}" align="center" y="{posy(banner1)} + {height(banner1)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesfanart1height} / {seriesfanart1width}"/>
+ <drawimage name="banner2" imagetype="image" path="{seriesbanner2path}" align="center" y="{posy(fanart1)} + {height(fanart1)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner2height} / {seriesbanner2width}"/>
+ <drawimage name="fanart2" imagetype="image" path="{seriesfanart2path}" align="center" y="{posy(banner2)} + {height(banner2)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesfanart2height} / {seriesfanart2width}"/>
+ <drawimage name="banner3" imagetype="image" path="{seriesbanner3path}" align="center" y="{posy(fanart2)} + {height(fanart2)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesbanner3height} / {seriesbanner3width}"/>
+ <drawimage name="fanart3" imagetype="image" path="{seriesfanart3path}" align="center" y="{posy(banner3)} + {height(banner3)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {seriesfanart3height} / {seriesfanart3width}"/>
+ <drawimage name="poster1" imagetype="image" path="{seriesposter1path}" align="center" y="{posy(fanart3)} + {height(fanart3)} + 20" width="{areawidth}*0.5" height="{areawidth} * 0.5 * {seriesposter1height} / {seriesposter1width}"/>
+ <drawimage name="poster2" imagetype="image" path="{seriesposter2path}" align="center" y="{posy(poster1)} + {height(poster1)} + 20" width="{areawidth}*0.5" height="{areawidth} * 0.5 * {seriesposter2height} / {seriesposter2width}"/>
+ <drawimage name="poster3" imagetype="image" path="{seriesposter3path}" align="center" y="{posy(poster2)} + {height(poster2)} + 20" width="{areawidth}*0.5" height="{areawidth} * 0.5 * {seriesposter3height} / {seriesposter3width}"/>
+ </tab>
+ <tab condition="{ismovie}" name="MovieDBInfo" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="poster" imagetype="image" path="{posterpath}" x="70%" y="10" width="{areawidth}*0.3" height="{areawidth} * 0.3 * {posterheight} / {posterwidth}"/>
+ <drawtextbox x="0" y="10" width="96%" float="topright" floatwidth="{width(poster)} + 10" floatheight="{height(poster)} + 20" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{tr(originaltitle)}: {movieoriginalTitle}&#10;&#10;|{tr(genre)}: {moviegenres}&#10;&#10;||{movietagline}&#10;&#10;|{movieoverview}&#10;&#10;|{tr(budget)}: {moviebudget}$&#10;||{tr(revenue)}: {movierevenue}$&#10;&#10;||{tr(adult)}: {movieadult}&#10;||{tr(releasedate)}: {moviereleasedate}&#10;||{tr(runtime)}: {movieruntime} min&#10;||&#10;{tr(popularity)}: {moviepopularity}&#10;||&#10;{tr(voteaverage)}: {movievoteaverage}&#10;||&#10;{tr(homepage)}: {moviehomepage}|&#10;" />
+ </tab>
+ <tab condition="{ismovie}" name="{tr(moviegalery)}" x="2%" y="25%" width="94%" height="60%" layer="2" scrollheight="{areaheight}/4">
+ <drawimage name="fanart" imagetype="image" path="{fanartpath}" align="center" y="10" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {fanartheight} / {fanartwidth}"/>
+ <drawimage name="poster" imagetype="image" path="{posterpath}" align="center" y="{height(fanart)} + 30" width="{areawidth}*0.6" height="{areawidth} * 0.6 * {posterheight} / {posterwidth}"/>
+ <drawimage condition="{movieiscollection}" name="collectionfanart" imagetype="image" path="{collectionfanartpath}" align="center" y="{posy(poster)} + {height(poster)} + 20" width="{areawidth}*0.9" height="{areawidth} * 0.9 * {collectionfanartheight} / {collectionfanartwidth}"/>
+ <drawimage condition="{movieiscollection}" name="collectionposter" imagetype="image" path="{collectionposterpath}" align="center" y="{posy(collectionfanart)} + {height(collectionfanart)} + 20" width="{areawidth}*0.6" height="{areawidth} * 0.6 * {collectionposterheight} / {collectionposterwidth}"/>
+ </tab>
+
+ <!-- Available Variables tablabels:
+ {tabs[]} array with available tab labels
+ {tabs[title]} title of tab
+ {tabs[current]} true if tab is displayed currently
+ -->
+ <tablabels>
+ <area x="1%" y="85%" width="98%" height="5%" layer="3">
+ <loop name="tabs" x="0" y="0" orientation="horizontal">
+ <drawrectangle condition="{tabs[current]}" x="0" y="0" width="{width(label)}" height="100%" color="{clrDarkGreen}" />
+ <drawrectangle condition="not{tabs[current]}" x="0" y="0" width="{width(label)}" height="100%" color="{clrDarkGreen}" />
+ <drawrectangle condition="not{tabs[current]}" x="2" y="2" width="{width(label)} - 4" height="{areaheight}-4" color="{clrTransparent}" />
+ <drawtext name="label" x="0" valign="center" font="{vdrOsd}" fontsize="95%" color="{clrWhite}" text=" {tabs[title]} " />
+ </loop>
+ </area>
+ </tablabels>
+
+</menudetailedrecording>
diff --git a/skins/nopacity/xmlfiles/displaymenudetailtext.xml b/skins/nopacity/xmlfiles/displaymenudetailtext.xml
new file mode 100644
index 0000000..ee44e2a
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displaymenudetailtext.xml
@@ -0,0 +1,25 @@
+<menudetailedtext x="0" y="0" width="100%" height="100%" fadetime="0">
+ <background>
+ <area x="0" y="0" width="100%" height="100%" layer="1">
+ <fill color="{clrTransBlack}" />
+ <drawrectangle x="0" y="0" width="100%" height="10%" color="{clrDarkBlue}" />
+ </area>
+ <area x="0" y="0" width="100%" height="10%" layer="2">
+ <drawimage imagetype="skinpart" path="headertop" x="0" y="0" width="100%" height="100%"/>
+ </area>
+ </background>
+ <scrollbar>
+ <area x="97%" y="11%" width="2%" height="79%" layer="2">
+ <fill color="{clrDarkBlue}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrDarkGreen}" />
+ </area>
+ </scrollbar>
+ <!-- Available Variables in tab elements:
+ {text} detailed text
+ -->
+ <tab name="text" x="2%" y="11%" width="94%" height="79%" layer="2" scrollheight="{areaheight}/4">
+ <drawtextbox x="0" y="0" width="100%" font="{light}" fontsize="5%" color="{clrWhite}" text="{text}" />
+ </tab>
+
+</menudetailedtext> \ No newline at end of file
diff --git a/skins/nopacity/xmlfiles/displaymenumain.xml b/skins/nopacity/xmlfiles/displaymenumain.xml
new file mode 100644
index 0000000..ba82f48
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displaymenumain.xml
@@ -0,0 +1,138 @@
+<menumain x="0" y="0" width="100%" height="100%" fadetime="0" scaletvx="33%" scaletvy="10%" scaletvwidth="65%" scaletvheight="80%" >
+ <!-- Available Variables header:
+ {title} title of current menu
+ {vdrversion} running VDR Version
+ {hasicon} true if a menu icon is available
+ {icon} path of menu icon
+ -->
+ <header>
+ <area x="1%" y="0" width="64%" height="10%" layer="3">
+ <drawimage imagetype="icon" path="ico_vdrlogo" x="0" valign="center" width="{areaheight} * 0.9 * 160 / 70" height="{areaheight}*0.9"/>
+ <drawtext x="{areaheight} * 0.9 * 160 / 70 + 10" valign="center" font="{vdrOsd}" fontsize="50%" color="{clrWhite}" text="{vdrversion}" />
+ </area>
+ </header>
+
+ <!-- Available Variables timers:
+ {numtimers} number of active timers (max. 15 timers will be displayed)
+ {numtimerconflicts} number of current timer conflicts
+ {timer1exists} true if timer 1 available
+ {timer2exists} true if timer 2 available
+ ...
+ {timer15exists} true if timer 15 available
+ {timers[]} array with active timers (local and remote if remotetimers plugin is in use)
+ {timers[title]} title of timer
+ {timers[datetime]} date and time of timer
+ {timers[recording]} true if timer is recording currently
+ {timers[channelname]} name of channel for which timer is created
+ {timers[channelnumber]} number of channel
+ {timers[channelid]} ChannelID of channel
+ {timers[channellogoexists]} true if channel logo exists
+ -->
+ <timers>
+ <area x="85%" y="28%" width="14%" height="60%" layer="1">
+ <drawrectangle condition="gt({numtimers}, 0)" x="0" y="0" width="{areawidth}" height="{areaheight} / 4 * 99 / 100" color="{clrTransBlack}" />
+ <drawrectangle condition="gt({numtimers}, 1)" x="0" y="{areaheight} / 4" width="{areawidth}" height="{areaheight} / 4 * 99 / 100" color="{clrTransBlack}" />
+ <drawrectangle condition="gt({numtimers}, 2)" x="0" y="{areaheight} / 2" width="{areawidth}" height="{areaheight} / 4 * 99 / 100" color="{clrTransBlack}" />
+ <drawrectangle condition="gt({numtimers}, 3)" x="0" y="{areaheight} * 3 / 4" width="{areawidth}" height="{areaheight} / 4 * 99 / 100" color="{clrTransBlack}" />
+ </area>
+ <area x="85%" y="28%" width="14%" height="60%" layer="2">
+ <loop name="timers" x="0" y="0" orientation="vertical" columnwidth="100%" rowheight="{areaheight} / 4" overflow="cut">
+ <drawrectangle condition="{timers[recording]}" x="0" y="0" width="{columnwidth}" height="{rowheight} * 99 / 100" color="{clrTransRed}" />
+ <drawimage cache="true" name="logo" imagetype="channellogo" path="{timers[channelid]}" height="{rowheight} / 2" align="center" y="5" />
+ <drawtextbox x="5" y="{height(logo)}+2" width="{columnwidth}-10" align="center" maxlines="2" font="{vdrOsd}" fontsize="4%" color="{clrWhite}" text="{timers[title]}" />
+ <drawtext name="datetime" align="center" y="{rowheight}*84/100" font="{vdrOsd}" fontsize="4%" color="{clrWhite}" text="{timers[datetime]}" />
+ </loop>
+ </area>
+ </timers>
+
+ <scrollbar>
+ <area x="30%" y="11%" width="2%" height="78%" layer="2">
+ <fill color="{clrDarkBlue}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrDarkGreen}" />
+ </area>
+ </scrollbar>
+
+ <!-- Available Variables discusage:
+ {freetime} available disc capacity in hh:mm
+ {freepercent} available disc capacity in percent
+ {usedpercent} used disc capacity in percent
+ {freegb} available disc capacity in gigabytes
+ {discalert} true if disc usage is > 95%
+ {vdrusagestring} localized VDR internal usage string
+ -->
+ <discusage>
+ <area x="89%" y="11%" width="10%" height="16%" layer="1">
+ <fill condition="lt({freepercent}, 6)" color="{clrTransRed}" />
+ <fill condition="gt({freepercent}, 5)" color="{clrDarkBlue}" />
+ <drawimage imagetype="skinpart" path="discpercent" x="0" y="82%" width="{areawidth}" height="18%"/>
+ </area>
+ <area x="89%" y="11%" width="10%" height="16%" layer="2">
+ <drawimage imagetype="icon" path="ico_discusage" align="center" y="2" width="{areawidth}*65/100" height="{areawidth}*65/100"/>
+ <drawtext align="center" y="42%" font="{vdrOsd}" fontsize="18%" color="{clrWhite}" text="{freetime}h {tr(free)}" />
+ <drawrectangle x="{areawidth}*{usedpercent}/100" y="82%" width="{areawidth} - {areawidth}*{usedpercent}/100" height="18%" color="{clrTransBlack}" />
+ <drawtext align="center" y="82%" font="{vdrOsd}" fontsize="19%" color="{clrWhite}" text="{usedpercent}%" />
+ </area>
+ </discusage>
+
+ <!-- Available Variables devices:
+ {numdevices} number of available devices
+ {devices[]} array with available devices
+ {devices[num]} number of current device
+ {devices[type]} type of device (DVB-S, DVB-C, ...)
+ {devices[istuned]} true if device is currently tuned to a transponder
+ {devices[livetv]} true if device is currently playing livetv
+ {devices[recording]} true if device is currently recording
+ {devices[hascam]} true if device has a CAM
+ {devices[cam]} number of CAM
+ {devices[signalstrength]} signalstrength of devcie
+ {devices[signalquality]} signalstrength of devcie
+ {devices[channelnumber]} number of the currently tuned channel
+ {devices[channelname]} name of the currently tuned channel
+ {devices[channelid]} ID of the currently tuned channel
+ {devices[source]} source of the currently tuned channel
+ -->
+ <devices>
+ </devices>
+
+ <!-- Available Variables systemload:
+ {load} current system load
+ -->
+ <systemload>
+ </systemload>
+
+ <menuitems x="{areawidth}*0.005" y="10%" orientation="vertical" width="28%" height="80%" align="center" numlistelements="10">
+ <!-- Available Variables main menu listelement:
+ {label} label of menu item
+ {number} number of menu item (or empty string if not set)
+ {icon} path of appropriate icon
+ {current} true if item is currently selected
+ {separator} true if item is a list separator
+ -->
+ <listelement>
+ <area x="0" width="100%" layer="2">
+ <drawimage condition="not{current}" imagetype="skinpart" path="menubutton" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ <drawimage condition="{current}" imagetype="skinpart" path="menubuttonactive" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ </area>
+ <area x="0" width="100%" layer="7">
+ <drawimage imagetype="skinpart" path="menubuttontop" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ </area>
+ <area x="0" width="100%" layer="3">
+ <drawimage imagetype="menuicon" path="{icon}" x="10" valign="center" width="{areaheight}*0.8" height="{areaheight}*0.8"/>
+ </area>
+ <areascroll scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="23%" width="77%" layer="3">
+ <drawtext condition="not{current}" name="menutext" x="0" valign="center" font="{vdrOsd}" fontsize="50%" color="{clrFontMenuItem}" text="{number} {label}" />
+ <drawtext condition="{current}" name="menutext" x="0" valign="center" font="{vdrOsd}" fontsize="50%" color="{clrFontMenuItemSelected}" text="{number} {label}" />
+ </areascroll>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables main menu currentelement:
+ {label} label of menu item
+ {number} number of menu item (or empty string if not set)
+ {icon} path of appropriate icon
+ -->
+ <currentelement delay="50" fadetime="0">
+ </currentelement>
+ </menuitems>
+
+</menumain>
diff --git a/skins/nopacity/xmlfiles/displaymenurecordings.xml b/skins/nopacity/xmlfiles/displaymenurecordings.xml
new file mode 100644
index 0000000..e6dbc4d
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displaymenurecordings.xml
@@ -0,0 +1,93 @@
+<menurecordings x="0" y="0" width="100%" height="100%" fadetime="0" scaletvx="33%" scaletvy="10%" scaletvwidth="65%" scaletvheight="80%">
+ <scrollbar>
+ <area x="30%" y="11%" width="2%" height="78%" layer="2">
+ <fill color="{clrDarkBlue}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrDarkGreen}" />
+ </area>
+ </scrollbar>
+
+ <menuitems x="{areawidth}*0.005" y="10%" orientation="vertical" width="99%" height="80%" align="center" numlistelements="10">
+ <!-- Available Variables recordings menu listelement:
+ {name} Name of recording
+ {date} Date of recording
+ {time} Time of recording
+ {duration} real duration of recording in minutes
+ {durationevent} duration of corresponding event in minutes
+ {current} true if item is currently selected
+ {new} true if recording is new
+ {cutted} true if recording is cutted
+ {folder} true if item is a folder
+ {numrecordingsfolder} if item is a folder, number of recordings in this folder
+ {newrecordingsfolder} if item is a folder, number of new recordings in this folder
+ {hasposterthumbnail} true if a scraped poster thumbnail is available for recording
+ {thumbnailbwidth} width of scraped poster thumbnail
+ {thumbnailheight} height of scraped poster thumbnail
+ {thumbnailpath} absolute path of scraped poster thumbnail
+ -->
+ <listelement>
+ <!-- background and foreground-->
+ <area x="0" width="28%" layer="2">
+ <drawimage condition="not{current}" imagetype="skinpart" path="menubutton" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ <drawimage condition="{current}" imagetype="skinpart" path="menubuttonactive" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ </area>
+ <!-- Folders -->
+ <area condition="{folder}" x="1%" width="27%" layer="3">
+ <drawimage name="foldericon" imagetype="icon" path="ico_recfolder" x="0" width="0.9*{areaheight} * 92 / 136" height="0.9*{areaheight}" valign="center" />
+ </area>
+ <areascroll condition="{folder}" scrollelement="foldername" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="5%" width="23%" layer="3">
+ <drawtext condition="not{current}" name="foldername" x="0" valign="center" font="{vdrOsd}" fontsize="50%" color="{clrFontMenuItem}" text="{name} ({numrecordingsfolder}, {newrecordingsfolder} new)" />
+ <drawtext condition="{current}" name="foldername" x="0" valign="center" font="{vdrOsd}" fontsize="50%" color="{clrFontMenuItemSelected}" text="{name} ({numrecordingsfolder}, {newrecordingsfolder} new)" />
+ </areascroll>
+ <!-- Recording -->
+ <area condition="{hasposterthumbnail}++not{folder}" x="1%" width="4%" layer="3">
+ <drawimage imagetype="image" path="{thumbnailpath}" x="0" width="0.9*{areaheight} * {thumbnailbwidth} / {thumbnailheight}" height="0.9*{areaheight}" valign="center" />
+ </area>
+ <areascroll condition="not{folder}" scrollelement="recname" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="5%" width="23%" layer="3">
+ <drawtext condition="not{current}" name="recname" x="0" y="5" font="{vdrOsd}" fontsize="50%" color="{clrFontMenuItem}" text="{name}" />
+ <drawtext condition="{current}" name="recname" x="0" y="5" font="{vdrOsd}" fontsize="50%" color="{clrFontMenuItemSelected}" text="{name}" />
+ </areascroll>
+ <area condition="not{folder}" x="5%" width="23%" layer="3">
+ <drawtext condition="not{current}" x="0" y="55%" font="{vdrOsd}" fontsize="40%" color="{clrFontMenuItem}" text="{date} {time}" />
+ <drawtext condition="{current}" x="0" y="55%" font="{vdrOsd}" fontsize="40%" color="{clrFontMenuItemSelected}" text="{date} {time}" />
+ <drawimage condition="{new}" name="new" imagetype="icon" path="ico_recnew" x="{areawidth} - {areaheight}/2 - 5" y="50%" width="{areaheight}*4/10" height="{areaheight}*4/10" />
+ <drawimage condition="{new}++{cutted}" imagetype="icon" path="ico_cutted" x="{areawidth} - {areaheight} - 10" y="50%" width="{areaheight}*4/10" height="{areaheight}*4/10" />
+ <drawimage condition="not{new}++{cutted}" imagetype="icon" path="ico_cutted" x="{areawidth} - {areaheight}/2 - 5" y="50%" width="{areaheight}*4/10" height="{areaheight}*4/10" />
+ </area>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables channels menu currentelement:
+ {name} Name of recording
+ {shorttext} Short Text of recording
+ {description} Descrption of recording
+ {date} Date of recording
+ {time} Time of recording
+ {duration} real duration of recording in minutes
+ {durationevent} duration of corresponding event in minutes
+ {new} true if recording is new
+ {cutted} true if recording is cutted
+ {folder} true if item is a folder
+ {numrecordingsfolder} if item is a folder, number of recordings in this folder
+ {newrecordingsfolder} if item is a folder, number of new recordings in this folder
+ {hasposter} true if a scraped poster is available for recording
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ -->
+ <currentelement delay="500" fadetime="300">
+ <area x="32%" y="2%" width="67%" height="96%" layer="2">
+ <fill color="{clrTransBlack}" />
+ <!-- header -->
+ <drawtext name="title" x="1%" y="0" width="98%" font="{vdrOsd}" fontsize="8%" color="{clrWhite}" text="{name}" />
+ <drawtext name="shorttext" x="1%" y="{height(title)}" width="98%" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{shorttext}" />
+ <drawtext name="datetime" x="1%" y="{posy(shorttext)} + {height(shorttext)}" font="{vdrOsd}" fontsize="5%" color="{clrWhite}" text="{date} {time}, {duration} min" />
+ <!-- scraper poster -->
+ <drawimage condition="{hasposter}" name="poster" imagetype="image" path="{posterpath}" x="3*{areawidth}/4" y="{posy(datetime)} + {height(datetime)} + 20" width="{areawidth}/4" height="{areawidth}/4 * {posterheight} / {posterwidth}"/>
+ <!-- description -->
+ <drawtextbox condition="{hasposter}" x="1%" y="{posy(poster)}" width="98%" height="{areaheight} - {posy(poster)}" float="topright" floatwidth="{width(poster)} + 10" floatheight="{height(poster)} + 10" font="{vdrOsd}" fontsize="5%" color="{clrWhite}" text="{description}" />
+ <drawtextbox condition="not{hasposter}" x="1%" y="{posy(poster)}" width="98%" height="{areaheight} - {posy(poster)}" font="{vdrOsd}" fontsize="5%" color="{clrWhite}" text="{description}" />
+ </area>
+ </currentelement>
+ </menuitems>
+
+</menurecordings> \ No newline at end of file
diff --git a/skins/nopacity/xmlfiles/displaymenuschedules.xml b/skins/nopacity/xmlfiles/displaymenuschedules.xml
new file mode 100644
index 0000000..d6a27f7
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displaymenuschedules.xml
@@ -0,0 +1,211 @@
+<menuschedules x="0" y="0" width="100%" height="100%" fadetime="0" scaletvx="33%" scaletvy="10%" scaletvwidth="65%" scaletvheight="80%" >
+ <!-- Available Variables header:
+ {title} title of current menu
+ {vdrversion} running VDR Version
+ {channelnumber} Number of Channel of current event
+ {channelname} Name of current Channel of current event
+ {channellogoexists} true if a channel logo exists
+ {channelid} ChannelID as path to display channel logo
+ {whatson} true if menu "What's on" is displayed
+ {whatsonnow} true if menu "What's on now" is displayed
+ {whatsonnext} true if menu "What's on next" is displayed
+ -->
+ <header>
+ <area x="1%" y="0" width="64%" height="10%" layer="2">
+ <drawtext condition="{whatsonnow}||{whatsonnext}" x="5" valign="center" font="{vdrOsd}" fontsize="80%" color="{clrWhite}" text="{title}" />
+ <drawimage name="logo" condition="{whatson}" imagetype="channellogo" path="{channelid}" x="0" height="100%" align="left" valign="center" />
+ <drawtext condition="{whatson}" x="{width(logo)}+20" valign="center" font="{vdrOsd}" fontsize="50%" color="{clrWhite}" text="{channelnumber} - {channelname}" />
+ </area>
+ </header>
+
+
+ <scrollbar>
+ <area x="30%" y="11%" width="2%" height="78%" layer="2">
+ <fill color="{clrDarkBlue}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrDarkGreen}" />
+ </area>
+ </scrollbar>
+
+ <menuitems x="{areawidth}*0.005" y="10%" orientation="vertical" width="99%" height="80%" align="center" numlistelements="10">
+ <!-- Available Variables schedules menu listelement:
+ {title} title of event
+ {shorttext} shorttext of event
+ {start} event start time in hh::mm
+ {stop} event stop time
+ {day} day of current event
+ {date} date of current event in dd.mm.yy
+ {running} true if event is currently running
+ {elapsed} elapsed time of event, if not running 0
+ {duration} duration of event
+ {current} true if item is currently selected
+ {separator} true if item is a list separator
+ {channelid} ChannelID as path to display channel logo
+ {whatson} true if menu "What's on" is displayed
+ {whatsonnow} true if menu "What's on now" is displayed
+ {whatsonnext} true if menu "What's on next" is displayed
+ {timerpartitial} true if partitial timer is set for the event
+ {timerfull} true if full timer is set for the event
+ -->
+ <listelement>
+ <!-- background and foreground-->
+ <area x="0" width="28%" layer="2">
+ <drawimage condition="not{current}" imagetype="skinpart" path="menubutton" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ <drawimage condition="{current}" imagetype="skinpart" path="menubuttonactive" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ </area>
+ <area x="0" width="28%" layer="7">
+ <drawimage imagetype="skinpart" path="menubuttontop" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ </area>
+ <!-- element whatson -->
+ <area condition="not{separator}++{whatson}++not{current}" x="1%" width="27%" layer="3">
+ <drawtext x="0" y="5%" font="{vdrOsd}" fontsize="40%" color="{clrFontMenuItem}" text="{start} - {stop}" />
+ <drawimage condition="{timerfull}" imagetype="icon" path="ico_activetimer" x="{areawidth} - {areaheight}*5/10 - 10" y="10" width="{areaheight}*5/10" height="{areaheight}*5/10" />
+ <drawimage condition="{timerpartitial}" imagetype="icon" path="ico_activetimer" x="{areawidth} - {areaheight}*3/10 - 10" y="10" width="{areaheight}*3/10" height="{areaheight}*3/10" />
+ </area>
+ <areascroll scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" condition="not{separator}++{whatson}++not{current}" x="1%" width="27%" layer="3">
+ <drawtext name="menutext" x="0" y="40%" font="{vdrOsd}" fontsize="55%" color="{clrFontMenuItem}" text="{title}" />
+ </areascroll>
+ <!-- current element whatson -->
+ <area condition="not{separator}++{whatson}++{current}" x="1%" width="27%" layer="3">
+ <drawtext x="0" y="5%" font="{vdrOsd}" fontsize="40%" color="{clrFontMenuItemSelected}" text="{start} - {stop}" />
+ <drawimage condition="{timerfull}" imagetype="icon" path="ico_activetimer" x="{areawidth} - {areaheight}*5/10 - 10" y="10" width="{areaheight}*5/10" height="{areaheight}*5/10" />
+ <drawimage condition="{timerpartitial}" imagetype="icon" path="ico_activetimer" x="{areawidth} - {areaheight}*3/10 - 10" y="10" width="{areaheight}*3/10" height="{areaheight}*3/10" />
+ </area>
+ <areascroll scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" condition="not{separator}++{whatson}++{current}" x="1%" width="27%" layer="3">
+ <drawtext name="menutext" x="0" y="40%" font="{vdrOsd}" fontsize="55%" color="{clrFontMenuItemSelected}" text="{title}" />
+ </areascroll>
+ <!-- element whatsonnow -->
+ <area condition="not{separator}++{whatsonnow}" x="5" width="8%" layer="3">
+ <drawimage name="logo" imagetype="channellogo" path="{channelid}" x="0" height="100%" valign="center" />
+ </area>
+ <area condition="not{separator}++{whatsonnow}++not{current}" x="9%" width="18%" layer="3">
+ <drawtext x="0" y="5%" font="{vdrOsd}" fontsize="40%" color="{clrFontMenuItem}" text="{start} - {stop}" />
+ <drawimage condition="{timerfull}" imagetype="icon" path="ico_activetimer" x="{areawidth} - {areaheight}*5/10 - 10" y="10" width="{areaheight}*5/10" height="{areaheight}*5/10" />
+ <drawimage condition="{timerpartitial}" imagetype="icon" path="ico_activetimer" x="{areawidth} - {areaheight}*3/10 - 10" y="10" width="{areaheight}*3/10" height="{areaheight}*3/10" />
+ </area>
+ <areascroll scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" condition="not{separator}++{whatsonnow}++not{current}" x="9%" width="18%" layer="3">
+ <drawtext name="menutext" x="0" y="40%" font="{vdrOsd}" fontsize="55%" color="{clrFontMenuItem}" text="{title}" />
+ </areascroll>
+ <!-- current element whatsonnow -->
+ <area condition="not{separator}++{whatsonnow}++{current}" x="9%" width="18%" layer="3">
+ <drawtext x="0" y="5%" font="{vdrOsd}" fontsize="40%" color="{clrFontMenuItemSelected}" text="{start} - {stop}" />
+ <drawimage condition="{timerfull}" imagetype="icon" path="ico_activetimer" x="{areawidth} - {areaheight}*5/10 - 10" y="10" width="{areaheight}*5/10" height="{areaheight}*5/10" />
+ <drawimage condition="{timerpartitial}" imagetype="icon" path="ico_activetimer" x="{areawidth} - {areaheight}*3/10 - 10" y="10" width="{areaheight}*3/10" height="{areaheight}*3/10" />
+ </area>
+ <areascroll scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" condition="not{separator}++{whatsonnow}++{current}" x="9%" width="18%" layer="3">
+ <drawtext name="menutext" x="0" y="40%" font="{vdrOsd}" fontsize="55%" color="{clrFontMenuItemSelected}" text="{title}" />
+ </areascroll>
+ <!-- day or channel separator -->
+ <area condition="{separator}" x="0" width="28%" layer="3">
+ <drawimage name="sep" imagetype="icon" path="ico_daydelimiter" x="10" valign="center" width="{areaheight}-10" height="{areaheight}-10"/>
+ <drawtext x="{width(sep)} + 20" valign="center" font="{vdrOsd}" fontsize="60%" color="{clrFontInactive}" text="{title}" />
+ </area>
+ <!-- element whatsonnext -->
+ <area condition="not{separator}++{whatsonnext}" x="5" width="8%" layer="3">
+ <drawimage name="logo" imagetype="channellogo" path="{channelid}" x="0" height="100%" valign="center" />
+ </area>
+ <area condition="not{separator}++{whatsonnext}++not{current}" x="9%" width="18%" layer="3">
+ <drawtext x="0" y="5%" font="{vdrOsd}" fontsize="40%" color="{clrFontMenuItem}" text="{start} - {stop}" />
+ <drawimage condition="{timerfull}" imagetype="icon" path="ico_activetimer" x="{areawidth} - {areaheight}*5/10 - 10" y="10" width="{areaheight}*5/10" height="{areaheight}*5/10" />
+ <drawimage condition="{timerpartitial}" imagetype="icon" path="ico_activetimer" x="{areawidth} - {areaheight}*3/10 - 10" y="10" width="{areaheight}*3/10" height="{areaheight}*3/10" />
+ </area>
+ <areascroll scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" condition="not{separator}++{whatsonnext}++not{current}" x="9%" width="18%" layer="3">
+ <drawtext name="menutext" x="0" y="40%" font="{vdrOsd}" fontsize="55%" color="{clrFontMenuItem}" text="{title}" />
+ </areascroll>
+ <!-- current element whatsonnext -->
+ <area condition="not{separator}++{whatsonnext}++{current}" x="9%" width="18%" layer="3">
+ <drawtext x="0" y="5%" font="{vdrOsd}" fontsize="40%" color="{clrFontMenuItemSelected}" text="{start} - {stop}" />
+ <drawimage condition="{timerfull}" imagetype="icon" path="ico_activetimer" x="{areawidth} - {areaheight}*5/10 - 10" y="10" width="{areaheight}*5/10" height="{areaheight}*5/10" />
+ <drawimage condition="{timerpartitial}" imagetype="icon" path="ico_activetimer" x="{areawidth} - {areaheight}*3/10 - 10" y="10" width="{areaheight}*3/10" height="{areaheight}*3/10" />
+ </area>
+ <areascroll scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" condition="not{separator}++{whatsonnext}++{current}" x="9%" width="18%" layer="3">
+ <drawtext name="menutext" x="0" y="40%" font="{vdrOsd}" fontsize="55%" color="{clrFontMenuItemSelected}" text="{title}" />
+ </areascroll>
+ <!-- day or channel separator -->
+ <area condition="{separator}" x="0" width="28%" layer="3">
+ <drawimage name="sep" imagetype="icon" path="ico_daydelimiter" x="10" valign="center" width="{areaheight}-10" height="{areaheight}-10"/>
+ <drawtext x="{width(sep)} + 20" valign="center" font="{vdrOsd}" fontsize="60%" color="{clrFontInactive}" text="{title}" />
+ </area>
+ </listelement>
+ <!-- Available Variables schedules menu currentelement:
+ {title} title of event
+ {shorttext} shorttext of event
+ {description} detailed description of event
+ {start} event start time in hh::mm
+ {stop} event stop time
+ {day} day of current event
+ {date} date of current event in dd.mm.yy
+ {running} true if event is currently running
+ {elapsed} elapsed time of event, if not running 0
+ {duration} duration of event
+ {channelid} ChannelID as path to display channel logo
+ {hasposter} true if a scraped poster is available for this element
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {timerpartitial} true if partitial timer is set for the event
+ {timerfull} true if full timer is set for the event
+ {whatson} true if menu "What's on" is displayed
+ {whatsonnow} true if menu "What's on now" is displayed
+ {whatsonnext} true if menu "What's on next" is displayed
+ {schedule[]} array with next 10 schedules, only for whatsonnow and whatsonnext
+ {schedule[title]} title of event
+ {schedule[shorttext]} shorttext of event
+ {schedule[start]} start time of event in hh:mm
+ {schedule[stop]} stop time of event in hh:mm
+ -->
+ <currentelement delay="500" fadetime="300">
+ <area x="32%" y="2%" width="67%" height="96%" layer="2">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <area condition="{whatson}" x="32%" y="2%" width="67%" height="96%" layer="2">
+ <!-- title -->
+ <drawtext name="title" align="center" y="0" font="{vdrOsd}" width="{areawidth}-20" fontsize="8%" color="{clrWhite}" text="{title}" />
+ <!-- progress bar if event is running -->
+ <drawtext condition="{running}" name="start" x="{areawidth}/4 - {width(start)}" y="9%" font="vdrOsd}" fontsize="6%" color="{clrWhite}" text="{start}" />
+ <drawtext condition="{running}" name="stop" x="{areawidth}*3/4" y="9%" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{stop}" />
+ <drawellipse condition="{running}" x="{areawidth} / 4 + 5" y="{posy(start)} + {height(start)} / 2 - 6" width="11" height="11" quadrant="0" color="{clrDarkBlue}" />
+ <drawrectangle condition="{running}" x="{areawidth} / 4 + 10" y="{posy(start)} + {height(start)} / 2 - 6" width="{areawidth}/2 - 20" height="11" color="{clrDarkBlue}" />
+ <drawellipse condition="{running}" x="3 * {areawidth} / 4 - 16" y="{posy(start)} + {height(start)} / 2 - 6" width="11" height="11" quadrant="0" color="{clrDarkBlue}" />
+ <drawellipse condition="{running}" x="{areawidth} / 4 + 6" y="{posy(start)} + {height(start)} / 2 - 5" width="9" height="9" quadrant="0" color="{clrBrightGreen}" />
+ <drawrectangle condition="{running}" x="{areawidth} / 4 + 10" y="{posy(start)} + {height(start)} / 2 - 5" width="{areawidth}/2 * {elapsed} / {duration} - 20 * {elapsed} / {duration}" height="9" color="{clrBrightGreen}" />
+ <drawellipse condition="{running}" x="{areawidth} / 4 + 10 + {areawidth}/2 * {elapsed} / {duration} - 20 * {elapsed} / {duration} - 4" y="{posy(start)} + {height(start)} / 2 - 5" width="9" height="9" quadrant="0" color="{clrBrightGreen}" />
+ <!-- start and stop if event is not running -->
+ <drawtext condition="not{running}" x="10" y="9%" font="{vdrOsd}" fontsize="{areaheight}/20" color="{clrWhite}" text="{start} - {stop} ({duration} min)" />
+ <!-- scraper poster -->
+ <drawimage condition="{hasposter}" name="poster" imagetype="image" path="{posterpath}" x="{areawidth} - {areawidth}/3" y="{posy(start)} + {height(start)} + 10" width="{areawidth}/3" height="{areawidth}/3 * {posterheight} / {posterwidth}"/>
+ <!-- description -->
+ <drawtextbox condition="{hasposter}" x="10" y="{posy(poster)}" width="99%" height="{areaheight} - {posy(poster)}" float="topright" floatwidth="{width(poster)} + 10" floatheight="{height(poster)} + 20" font="{vdrOsd}" fontsize="{areaheight}/20" color="{clrWhite}" text="{description}" />
+ <drawtextbox condition="not{hasposter}" x="10" y="{posy(poster)}" width="99%" height="{areaheight} - {posy(poster)}" font="{vdrOsd}" fontsize="{areaheight}/20" color="{clrWhite}" text="{description}" />
+ </area>
+ <!-- whatsonnow and whotsonnext -->
+ <area condition="{whatsonnow}||{whatsonnext}" x="32%" y="2%" width="67%" height="76%" layer="2">
+ <!-- title -->
+ <drawtext align="center" y="0" font="{vdrOsd}" width="{areawidth}-20" fontsize="10%" color="{clrWhite}" text="{title}" />
+ <!-- progress bar if event is running -->
+ <drawtext condition="{running}" name="start" x="{areawidth}/4 - {width(start)}" y="11%" font="vdrOsd}" fontsize="8%" color="{clrWhite}" text="{start}" />
+ <drawtext condition="{running}" name="stop" x="{areawidth}*3/4" y="11%" font="{vdrOsd}" fontsize="8%" color="{clrWhite}" text="{stop}" />
+ <drawellipse condition="{running}" x="{areawidth} / 4 + 5" y="{posy(start)} + {height(start)} / 2 - 6" width="11" height="11" quadrant="0" color="{clrDarkBlue}" />
+ <drawrectangle condition="{running}" x="{areawidth} / 4 + 10" y="{posy(start)} + {height(start)} / 2 - 6" width="{areawidth}/2 - 20" height="11" color="{clrDarkBlue}" />
+ <drawellipse condition="{running}" x="3 * {areawidth} / 4 - 16" y="{posy(start)} + {height(start)} / 2 - 6" width="11" height="11" quadrant="0" color="{clrDarkBlue}" />
+ <drawellipse condition="{running}" x="{areawidth} / 4 + 6" y="{posy(start)} + {height(start)} / 2 - 5" width="9" height="9" quadrant="0" color="{clrBrightGreen}" />
+ <drawrectangle condition="{running}" x="{areawidth} / 4 + 10" y="{posy(start)} + {height(start)} / 2 - 5" width="{areawidth}/2 * {elapsed} / {duration} - 20 * {elapsed} / {duration}" height="9" color="{clrBrightGreen}" />
+ <drawellipse condition="{running}" x="{areawidth} / 4 + 10 + {areawidth}/2 * {elapsed} / {duration} - 20 * {elapsed} / {duration} - 4" y="{posy(start)} + {height(start)} / 2 - 5" width="9" height="9" quadrant="0" color="{clrBrightGreen}" />
+ <!-- start and stop if event is not running -->
+ <drawtext condition="not{running}" x="10" y="9%" font="{vdrOsd}" fontsize="{areaheight}/20" color="{clrWhite}" text="{start} - {stop} ({duration} min)" />
+ <!-- scraper poster -->
+ <drawimage condition="{hasposter}" name="poster" imagetype="image" path="{posterpath}" x="{areawidth}* 2 / 3" y="{posy(start)} + {height(start)} + 10" width="{areawidth}/3" height="{areawidth}/3 * {posterheight} / {posterwidth}"/>
+ <!-- description -->
+ <drawtextbox condition="{hasposter}" x="10" y="{posy(poster)}" width="99%" height="{areaheight} - {posy(poster)}" float="topright" floatwidth="{width(poster)} + 10" floatheight="{height(poster)} + 10" font="{vdrOsd}" fontsize="{areaheight}/18" color="{clrWhite}" text="{description}" />
+ <drawtextbox condition="not{hasposter}" x="10" y="{posy(poster)}" width="99%" height="{areaheight} - {posy(poster)}" font="{vdrOsd}" fontsize="{areaheight}/18" color="{clrWhite}" text="{description}" />
+ </area>
+ <areascroll condition="{whatsonnow}||{whatsonnext}" mode="forthandback" orientation="vertical" delay="1000" scrollspeed="medium" x="32%" y="78%" width="67%" height="20%" layer="2">
+ <drawtext x="10" y="0" font="{semibold}" fontsize="20%" color="{clrWhite}" text="{tr(nextschedules)}:" />
+ <loop name="schedule" x="0" y="{areaheight}/4 + 5" orientation="vertical">
+ <drawtext x="10" font="{vdrOsd}" width="{areawidth}-20" fontsize="20%" color="{clrWhite}" text="{schedule[start]} {schedule[title]}" />
+ </loop>
+ </areascroll>
+ </currentelement>
+ </menuitems>
+
+</menuschedules> \ No newline at end of file
diff --git a/skins/nopacity/xmlfiles/displaymenusetup.xml b/skins/nopacity/xmlfiles/displaymenusetup.xml
new file mode 100644
index 0000000..c0fd3d3
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displaymenusetup.xml
@@ -0,0 +1,45 @@
+<menusetup x="0" y="0" width="100%" height="100%" fadetime="0" scaletvx="33%" scaletvy="10%" scaletvwidth="65%" scaletvheight="80%" >
+
+ <scrollbar>
+ <area x="30%" y="11%" width="2%" height="78%" layer="2">
+ <fill color="{clrDarkBlue}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrDarkGreen}" />
+ </area>
+ </scrollbar>
+
+ <menuitems x="{areawidth}*0.005" y="10%" orientation="vertical" width="28%" height="80%" align="center" numlistelements="10">
+ <!-- Available Variables setup menu listelement:
+ {label} label of menu item
+ {number} number of menu item (or empty string if not set)
+ {icon} path of appropriate icon
+ {current} true if item is currently selected
+ {separator} true if item is a list separator
+ -->
+ <listelement>
+ <area x="0" width="100%" layer="2">
+ <drawimage condition="not{current}" imagetype="skinpart" path="menubutton" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ <drawimage condition="{current}" imagetype="skinpart" path="menubuttonactive" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ </area>
+ <area x="0" width="100%" layer="7">
+ <drawimage imagetype="skinpart" path="menubuttontop" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ </area>
+ <area x="0" width="100%" layer="3">
+ <drawimage imagetype="menuicon" path="{icon}" x="10" valign="center" width="{areaheight}*0.9" height="{areaheight}*0.9"/>
+ </area>
+ <areascroll scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="25%" width="75%" layer="3">
+ <drawtext condition="not{current}" name="menutext" x="0" valign="center" font="{vdrOsd}" fontsize="50%" color="{clrFontMenuItem}" text="{number} {label}" />
+ <drawtext condition="{current}" name="menutext" x="0" valign="center" font="{vdrOsd}" fontsize="50%" color="{clrFontMenuItemSelected}" text="{number} {label}" />
+ </areascroll>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables main menu currentelement:
+ {label} label of menu item
+ {number} number of menu item (or empty string if not set)
+ {icon} path of appropriate icon
+ -->
+ <currentelement delay="50" fadetime="0">
+ </currentelement>
+ </menuitems>
+
+</menusetup>
diff --git a/skins/nopacity/xmlfiles/displaymenutimers.xml b/skins/nopacity/xmlfiles/displaymenutimers.xml
new file mode 100644
index 0000000..0c14138
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displaymenutimers.xml
@@ -0,0 +1,98 @@
+<menutimers x="0" y="0" width="100%" height="100%" fadetime="0" scaletvx="33%" scaletvy="10%" scaletvwidth="65%" scaletvheight="80%">
+ <scrollbar>
+ <area x="30%" y="11%" width="2%" height="78%" layer="2">
+ <fill color="{clrDarkBlue}" />
+ <drawrectangle x="2" y="2" width="{areawidth} - 4" height="{areaheight} - 4" color="{clrTransparent}" />
+ <drawrectangle x="4" y="4 + {areaheight} * {offset} / 1000" width="{areawidth} - 8" height="{areaheight} * {height} / 1000 - 8" color="{clrDarkGreen}" />
+ </area>
+ </scrollbar>
+
+ <menuitems x="{areawidth}*0.005" y="10%" orientation="vertical" width="99%" height="80%" align="center" numlistelements="10">
+ <!-- Available Variables channels menu listelement:
+ {title} Title of Timer
+ {timerstart} Start Time of Timer in hh::mm
+ {timerstop} End Time of Timer in hh::mm
+ {day} Day (numerical)
+ {dayname} Day, for repeating timers days where timer is active
+ {channelname} Name of channel which is set for the timer
+ {channelid} ID of channel which is set for the timer (for dispalying channel logo)
+ {channelnumber} Number of channel which is set for the timer
+ {eventtitle} Title of corresponding event
+ {eventstart} Start Time of corresponding event in hh::mm
+ {eventstop} Stop Time of corresponding event in hh::mm
+ {current} true if item is currently selected
+ {flagactive} true if timer is active
+ {flaginstant} true if timer is an instant timer
+ {flagvps} true if timer uses VPS
+ {flagrecording} true if is recording currently
+ {flagpending} true if timer is pending
+ -->
+ <listelement>
+ <!-- background and foreground-->
+ <area x="0" width="28%" layer="2">
+ <drawimage condition="not{current}" imagetype="skinpart" path="menubutton" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ <drawimage condition="{current}" imagetype="skinpart" path="menubuttonactive" x="0" y="1%" width="{areawidth}" height="{areaheight}*0.98"/>
+ </area>
+ <!-- channel logo -->
+ <area x="5" width="6%" layer="3">
+ <drawimage imagetype="channellogo" path="{channelid}" x="0" height="100%" valign="center" />
+ </area>
+ <!-- datetime and icons -->
+ <area x="1%" width="28%" layer="3">
+ <drawtext condition="not{current}" x="22%" y="5" font="{vdrOsd}" fontsize="40%" color="{clrFontMenuItem}" text="{dayname} {day}. {timerstart} - {timerstop}" />
+ <drawtext condition="{current}" x="22%" y="5" font="{vdrOsd}" fontsize="40%" color="{clrFontMenuItemSelected}" text="{dayname} {day}. {timerstart} - {timerstop}" />
+ <drawimage condition="{flagactive}" imagetype="icon" path="ico_timer_active" x="{areawidth} - 0.5*{areaheight} - 20" y="0" width="0.5*{areaheight}" height="0.5*{areaheight}" />
+ <drawimage condition="not{flagactive}" imagetype="icon" path="ico_timer_inactive" x="{areawidth} - 0.5*{areaheight} - 20" y="0" width="0.5*{areaheight}" height="0.5*{areaheight}" />
+ <drawimage condition="{flagrecording}" name="active" imagetype="icon" path="ico_timer_recording" x="{areawidth} - {areaheight} - 20" y="0" width="0.5*{areaheight}" height="0.5*{areaheight}" />
+ </area>
+ <!-- Timer Name -->
+ <areascroll scrollelement="timername" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="7%" width="20%" layer="3">
+ <drawtext condition="not{current}" name="timername" x="0" y="50%" font="{vdrOsd}" fontsize="50%" color="{clrFontMenuItem}" text="{title}" />
+ <drawtext condition="{current}" name="timername" x="0" y="50%" font="{vdrOsd}" fontsize="50%" color="{clrFontMenuItemSelected}" text="{title}" />
+ </areascroll>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables channels menu currentelement:
+ {title} Title of Timer
+ {timerstart} Start Time of Timer in hh::mm
+ {timerstop} End Time of Timer in hh::mm
+ {day} Day (numerical)
+ {dayname} Day, for repeating timers days where timer is active
+ {channelname} Name of channel which is set for the timer
+ {channelid} ID of channel which is set for the timer (for dispalying channel logo)
+ {channelnumber} Number of channel which is set for the timer
+ {eventtitle} Title of corresponding event
+ {eventstart} Start Time of corresponding event in hh::mm
+ {eventstop} Stop Time of corresponding event in hh::mm
+ {eventshorttext} Short Text corresponding event
+ {eventdescription} Description corresponding event
+ {hasposter} true if a scraped poster is available for event
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {flagactive} true if timer is active
+ {flaginstant} true if timer is an instant timer
+ {flagvps} true if timer uses VPS
+ {flagrecording} true if is recording currently
+ {flagpending} true if timer is pending
+ -->
+ <currentelement delay="500" fadetime="300">
+ <area x="32%" y="2%" width="67%" height="96%" layer="2">
+ <fill color="{clrTransBlack}" />
+ </area>
+ <area x="32%" y="2%" width="67%" height="96%" layer="2">
+ <!-- title -->
+ <drawtext name="title" align="center" y="0" font="{vdrOsd}" width="{areawidth}-20" fontsize="8%" color="{clrWhite}" text="{eventtitle} - {eventshorttext}" />
+ <!-- start and stop if event is not running -->
+ <drawtext x="10" y="9%" font="{vdrOsd}" fontsize="6%" color="{clrWhite}" text="{dayname} {eventstart} - {eventstop}, {channelname}" />
+ <!-- scraper poster -->
+ <drawimage condition="{hasposter}" name="poster" imagetype="image" path="{posterpath}" x="{areawidth} - {areawidth}/4" y="17%" width="{areawidth}/4" height="{areawidth}/4 * {posterheight} / {posterwidth}"/>
+ <!-- description -->
+ <drawtextbox condition="{hasposter}" x="10" y="{posy(poster)}" width="99%" height="{areaheight} - {posy(poster)}" float="topright" floatwidth="{width(poster)} + 10" floatheight="{height(poster)} + 20" font="{vdrOsd}" fontsize="5%" color="{clrWhite}" text="{eventdescription}" />
+ <drawtextbox condition="not{hasposter}" x="10" y="{posy(poster)}" width="99%" height="{areaheight} - {posy(poster)}" font="{vdrOsd}" fontsize="5%" color="{clrWhite}" text="{eventdescription}" />
+ </area>
+ </currentelement>
+
+ </menuitems>
+
+</menutimers> \ No newline at end of file
diff --git a/skins/nopacity/xmlfiles/displaymessage.xml b/skins/nopacity/xmlfiles/displaymessage.xml
new file mode 100644
index 0000000..c5cbff2
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displaymessage.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displaymessage SYSTEM "../../dtd/displaymessage.dtd">
+
+<displaymessage x="0" y="0" width="100%" height="100%" fadetime="300">
+
+ <background>
+ </background>
+
+ <!-- Available Variables message:
+ {text} message text
+ {status} true if message is a status message
+ {info} true if message is a info message
+ {warning} true if message is a warn message
+ {error} true if message is a error message
+ -->
+ <message>
+ <area x="5%" y="80%" width="90%" height="15%" layer="6">
+ <drawimage condition="{status}" imagetype="skinpart" path="messageStatus" x="0" y="0" width="100%" height="100%" />
+ <drawimage condition="{info}" imagetype="skinpart" path="messageInfo" x="0" y="0" width="100%" height="100%" />
+ <drawimage condition="{warning}" imagetype="skinpart" path="messageWarning" x="0" y="0" width="100%" height="100%" />
+ <drawimage condition="{error}" imagetype="skinpart" path="messageError" x="0" y="0" width="100%" height="100%" />
+ </area>
+ <area x="5%" y="80%" width="90%" height="15%" layer="7">
+ <drawtext align="center" valign="center" font="{light}" fontsize="40%" color="{clrWhite}" text="{text}" />
+ </area>
+ </message>
+
+</displaymessage>
diff --git a/skins/nopacity/xmlfiles/displayreplay.xml b/skins/nopacity/xmlfiles/displayreplay.xml
new file mode 100644
index 0000000..dee1375
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displayreplay.xml
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displayreplay SYSTEM "../../dtd/displayreplay.dtd">
+
+<displayreplay x="0" y="0" width="100%" height="100%" fadetime="{fadeTime}">
+
+ <background>
+ <area x="1%" y="74%" width="98%" height="25%" layer="1" transparency="20">
+ <drawimage imagetype="skinpart" path="displayreplayback" x="0" y="0" width="100%" height="100%"/>
+ </area>
+ <area x="1%" y="74%" width="98%" height="25%" layer="7">
+ <drawimage imagetype="skinpart" path="displayreplaytop" x="0" y="0" width="100%" height="100%"/>
+ </area>
+ <!-- background progress bar -->
+ <area x="3%" y="83%" width="94%" height="2%" layer="2">
+ <drawellipse x="0" y="0" width="{areaheight}" height="{areaheight}" color="{clrBlack}" quadrant="0" />
+ <drawellipse x="{areawidth}-{areaheight}" y="0" width="{areaheight}" height="{areaheight}" color="{clrBlack}" quadrant="0" />
+ <drawrectangle x="{areaheight}/2" y="0" width="{areawidth} - {areaheight}" height="{areaheight}" color="{clrBlack}" />
+ </area>
+ </background>
+
+ <backgroundmodeonly>
+ <area x="40%" y="86%" width="20%" height="11%" layer="3">
+ <fill color="{clrBrightGreen}" />
+ <drawrectangle x="1" y="1" width="{areawidth} -2" height="{areaheight} -2" color="{clrTransBlack}" />
+ </area>
+ </backgroundmodeonly>
+
+ <!-- Available Variables datetime:
+ {time} time in hh:mm
+ {day} day in digits
+ {dayleadingzero} day in digits with leading 0
+ {dayname} Full name of the day
+ {daynameshort} Short 3 char name of the day
+ {month} month in digits with leading 0
+ {monthname} Full name of the month
+ {year} year in yyyy
+ -->
+ <datetime>
+ <area x="63%" y="74%" width="35%" height="6%" layer="2">
+ <drawtext align="right" valign="center" font="{vdrOsd}" fontsize="95%" color="{clrWhite}" width="100%" text="{daynameshort} {day}.{month} {time}" />
+ </area>
+ </datetime>
+
+ <!-- Available Variables scrapercontent:
+ {mediapath} Full Path of Poster or Banner to use in image path attribute
+ {mediawidth} width of image in pixel
+ {mediaheight} height of image in pixel
+ {isbanner} true if image is a banner, false if it is a poster
+ -->
+ <scrapercontent>
+ <area condition="{isbanner}" x="0" y="0" width="{areaheight}*0.13*{mediawidth}/{mediaheight}" height="13%" layer="2">
+ <drawimage imagetype="image" path="{mediapath}" align="center" valign="center" width="{areawidth}" height="{areaheight}"/>
+ </area>
+ <area condition="not{isbanner}" x="0" y="0" width="{areaheight}*0.5*{mediawidth}/{mediaheight}" height="50%" layer="2">
+ <drawimage imagetype="image" path="{mediapath}" x="5" y="5" width="{areawidth}-10" height="{areaheight}-10"/>
+ </area>
+ </scrapercontent>
+
+ <!-- Available Variables rectitle:
+ {rectitle} Title of Recording
+ {recsubtitle} Subtitle of the Recording
+ {recdate} Date Recording in dd.mm.yy
+ {rectime} Time of Recording in hh:mm
+ -->
+ <rectitle>
+ <area x="3%" y="74%" width="60%" height="6%" layer="2">
+ <drawtext name="title" x="0" valign="center" font="{vdrOsd}" fontsize="95%" color="{clrWhite}" width="100%" text="{rectitle}" />
+ <drawtext condition="isset{recsubtitle}" x="{width(title)}" valign="center" font="{vdrOsd}" fontsize="95%" color="{clrWhite}" width="100%" text=" - {recsubtitle}" />
+ </area>
+ </rectitle>
+
+ <!-- Available Variables recinfo:
+ {screenwidth} width of currently displayed recording in px
+ {screenheight} height of currently displayed recording in px
+ {resolution} resolution: hd1080i, hd720p, sd576i
+ {aspect} screen aspect, each 4:3, 16:9 or 21:9
+ {isHD} true for hd1080i and hd720p
+ {isWideScreen} true if aspect is 16:9 or 21:9
+ -->
+ <recinfo>
+ <area x="{areawidth}*0.98 - {areaheight}*0.15" y="93%" width="{areaheight}*0.15" height="5%" layer="2">
+ <drawimage imagetype="icon" path="ico_{resolution}" x="0" y="0" width="{areaheight}*3" height="{areaheight}"/>
+ </area>
+ </recinfo>
+
+ <!-- Available Variables currenttime:
+ {reccurrent} Current Time in hh:mm:ss
+ -->
+ <currenttime>
+ <area x="3%" y="86%" width="30%" height="4%" layer="2">
+ <drawtext x="0" valign="center" font="{vdrOsd}" fontsize="100%" color="{clrWhite}" text="{reccurrent}" />
+ </area>
+ </currenttime>
+
+ <!-- Available Variables totaltime:
+ {rectotal} Total Time in hh:mm:ss
+ -->
+ <totaltime>
+ <area x="67%" y="86%" width="30%" height="4%" layer="2">
+ <drawtext align="right" valign="center" font="{vdrOsd}" fontsize="100%" color="{clrWhite}" text="{rectotal}" />
+ </area>
+ </totaltime>
+
+ <!-- Available Variables progressbar:
+ {current} current frame of recording
+ {total} total frames of recording
+ -->
+ <progressbar>
+ <area x="3%" y="83%" width="94%" height="2%" layer="2">
+ <drawellipse x="1" y="1" width="{areaheight}-2" height="{areaheight}-2" color="{clrBrightGreen}" quadrant="0" />
+ <drawrectangle x="{areaheight}/2" y="1" width="{current}/{total}*{areawidth} - {current}/{total}*{areaheight}" height="{areaheight}-2" color="{clrBrightGreen}" />
+ </area>
+ </progressbar>
+
+ <!-- Available Variables cutmarks:
+ {marks[]} array of available marks
+ {marks[position]} frame of current mark
+ {marks[endposition]} frame where startmark ends
+ {marks[total]} total number of frames
+ {marks[startmark]} true if mark is start mark
+ -->
+ <cutmarks>
+ <area x="3%" y="82%" width="94%" height="4%" layer="3">
+ <loop name="marks" x="0" y="0" orientation="absolute">
+ <drawrectangle x="{marks[position]}/{marks[total]}*{areawidth}" y="0" width="1" height="100%" color="{clrTransWhite}" />
+ <drawrectangle condition="{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth}" y="0" width="5" height="1" color="{clrTransWhite}" />
+ <drawrectangle condition="{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth}" y="{areaheight}-1" width="5" height="1" color="{clrTransWhite}" />
+ <drawrectangle condition="not{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth} - 5" y="0" width="5" height="1" color="{clrTransWhite}" />
+ <drawrectangle condition="not{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth} - 5" y="{areaheight}-1" width="5" height="1" color="{clrTransWhite}" />
+ <drawrectangle condition="{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth}" y="30%" width="{marks[endposition]}/{marks[total]}*{areawidth} - {marks[position]}/{marks[total]}*{areawidth}" height="40%" color="{clrTransWhite}" />
+ </loop>
+ </area>
+ </cutmarks>
+
+ <!-- Available Variables controlicons and controliconsmodeonly:
+ {play} true if recording is played currently
+ {pause} true if recording is paused
+ {forward} true if fast forwarding
+ {forward1x} true if fast forwarding 1x (with 3 trickspeeds)
+ {forward2x} true if fast forwarding 2x (with 3 trickspeeds)
+ {forward3x} true if fast forwarding 3x (with 3 trickspeeds)
+ {rewind} true if rewinding
+ {rewind1x} true if rewinding 1x (with 3 trickspeeds)
+ {rewind2x} true if rewinding 2x (with 3 trickspeeds)
+ {rewind3x} true if rewinding 3x (with 3 trickspeeds)
+ -->
+ <controlicons>
+ <area x="30%" y="88%" width="40%" height="7%" layer="3">
+ <drawimage condition="not{rewind} ++ not{rewind1x} ++ not{rewind2x} ++ not{rewind3x}" imagetype="icon" path="ico_rew_off" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind}" imagetype="icon" path="ico_rew" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind1x}" imagetype="icon" path="ico_rew_1x" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind2x}" imagetype="icon" path="ico_rew_2x" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind3x}" imagetype="icon" path="ico_rew_3x" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+
+ <drawimage condition="not{pause}" imagetype="icon" path="ico_pause_off" x="{areawidth}/2 - {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{pause}" imagetype="icon" path="ico_pause" x="{areawidth}/2 - {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+
+ <drawimage condition="not{play}" imagetype="icon" path="ico_play_off" x="{areawidth}/2" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{play}" imagetype="icon" path="ico_play" x="{areawidth}/2" y="0" width="{areaheight}" height="{areaheight}"/>
+
+ <drawimage condition="not{forward} ++ not{forward1x} ++ not{forward2x} ++ not{forward3x}" imagetype="icon" path="ico_ff_off" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward}" imagetype="icon" path="ico_ff" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward1x}" imagetype="icon" path="ico_ff_1x" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward2x}" imagetype="icon" path="ico_ff_2x" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward3x}" imagetype="icon" path="ico_ff_3x" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ </area>
+ </controlicons>
+
+ <controliconsmodeonly>
+ <area x="30%" y="88%" width="40%" height="7%" layer="3">
+ <drawimage condition="not{rewind} ++ not{rewind1x} ++ not{rewind2x} ++ not{rewind3x}" imagetype="icon" path="ico_rew_off" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind}" imagetype="icon" path="ico_rew" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind1x}" imagetype="icon" path="ico_rew_1x" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind2x}" imagetype="icon" path="ico_rew_2x" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{rewind3x}" imagetype="icon" path="ico_rew_3x" x="{areawidth}/2 - 2*{areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+
+ <drawimage condition="not{pause}" imagetype="icon" path="ico_pause_off" x="{areawidth}/2 - {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{pause}" imagetype="icon" path="ico_pause" x="{areawidth}/2 - {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+
+ <drawimage condition="not{play}" imagetype="icon" path="ico_play_off" x="{areawidth}/2" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{play}" imagetype="icon" path="ico_play" x="{areawidth}/2" y="0" width="{areaheight}" height="{areaheight}"/>
+
+ <drawimage condition="not{forward} ++ not{forward1x} ++ not{forward2x} ++ not{forward3x}" imagetype="icon" path="ico_ff_off" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward}" imagetype="icon" path="ico_ff" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward1x}" imagetype="icon" path="ico_ff_1x" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward2x}" imagetype="icon" path="ico_ff_2x" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{forward3x}" imagetype="icon" path="ico_ff_3x" x="{areawidth}/2 + {areaheight}" y="0" width="{areaheight}" height="{areaheight}"/>
+ </area>
+ </controliconsmodeonly>
+
+ <!-- Available Variables jump:
+ {jump} time to jump to in hh:mm
+ -->
+ <jump>
+ <area x="5%" y="90%" width="30%" height="7%" layer="2">
+ <drawtext align="center" valign="center" font="{vdrOsd}" fontsize="80%" color="{clrWhite}" text="{jump}" />
+ </area>
+ </jump>
+ <!-- Available Variables message:
+ {text} message text
+ {status} true if message is a status message
+ {info} true if message is a info message
+ {warning} true if message is a warn message
+ {error} true if message is a error message
+ -->
+ <message>
+ <area x="5%" y="58%" width="90%" height="15%" layer="6">
+ <drawimage condition="{status}" imagetype="skinpart" path="messageStatus" x="0" y="0" width="100%" height="100%" />
+ <drawimage condition="{info}" imagetype="skinpart" path="messageInfo" x="0" y="0" width="100%" height="100%" />
+ <drawimage condition="{warning}" imagetype="skinpart" path="messageWarning" x="0" y="0" width="100%" height="100%" />
+ <drawimage condition="{error}" imagetype="skinpart" path="messageError" x="0" y="0" width="100%" height="100%" />
+ </area>
+ <area x="5%" y="58%" width="90%" height="15%" layer="7">
+ <drawtext align="center" valign="center" font="{light}" fontsize="40%" color="{clrWhite}" text="{text}" />
+ </area>
+ </message>
+
+</displayreplay>
diff --git a/skins/nopacity/xmlfiles/displayvolume.xml b/skins/nopacity/xmlfiles/displayvolume.xml
new file mode 100644
index 0000000..9cd176a
--- /dev/null
+++ b/skins/nopacity/xmlfiles/displayvolume.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displayvolume SYSTEM "../../dtd/displayvolume.dtd">
+
+<displayvolume x="20%" y="75%" width="60%" height="10%" fadetime="{fadeTime}">
+
+ <background>
+ </background>
+
+ <!-- Available Variables volume:
+ {volume} current volume, range from 0 to 255
+ {volumepercent} current volume in %
+ {maxvolume} maximal volume
+ {mute} true if volume is muted
+ -->
+ <volume>
+ <!-- Background -->
+ <area x="0" y="0" width="100%" height="100%" layer="1" transparency="20">
+ <drawimage imagetype="skinpart" path="displayvolume" x="0" y="0" width="100%" height="100%"/>
+ </area>
+ <!-- Header -->
+ <area x="0" y="3%" width="100%" height="40%" layer="2">
+ <drawtext x="10" valign="center" font="{vdrOsd}" fontsize="100%" color="{clrWhite}" text="{tr(volume)}: {volumepercent}%" />
+ <drawimage condition="not{mute}" imagetype="icon" path="ico_volume" x="{areawidth} - 2*{areaheight}" y="5" width="{areaheight}" height="{areaheight}"/>
+ <drawimage condition="{mute}" imagetype="icon" path="ico_mute" x="{areawidth} - 2*{areaheight}" y="5" width="{areaheight}" height="{areaheight}"/>
+ </area>
+ <!-- Volumebar Background -->
+ <area x="4%" y="60%" width="92%" height="30%" layer="2">
+ <drawellipse x="0" y="0" width="{areaheight}" height="{areaheight}" color="{clrBlack}" quadrant="0" />
+ <drawellipse x="1" y="1" width="{areaheight}-2" height="{areaheight}-2" color="{clrBrightGreen}" quadrant="0" />
+ <drawellipse x="{areawidth}-{areaheight}" y="0" width="{areaheight}" height="{areaheight}" color="{clrBlack}" quadrant="0" />
+ <drawrectangle x="{areaheight}/2" y="0" width="{areawidth} - {areaheight}" height="{areaheight}" color="{clrBlack}" />
+ </area>
+ <!-- Volumebar -->
+ <area x="5%" y="60%" width="91%" height="30%" layer="3">
+ <drawrectangle x="1" y="1" width="{volume}/{maxvolume}*{areawidth} - {volume}/{maxvolume}*{areaheight}/2" height="{areaheight}-2" color="{clrBrightGreen}" />
+ <drawellipse x="{volume}/{maxvolume}*{areawidth} - {volume}/{maxvolume}*{areaheight}/2" y="1" width="{areaheight}/2 - 2" height="{areaheight}-2" color="{clrBrightGreen}" quadrant="5" />
+ </area>
+ </volume>
+
+</displayvolume>
diff --git a/skins/nopacity/xmlfiles/globals.xml b/skins/nopacity/xmlfiles/globals.xml
new file mode 100644
index 0000000..1870789
--- /dev/null
+++ b/skins/nopacity/xmlfiles/globals.xml
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE globals SYSTEM "../../dtd/globals.dtd">
+
+<globals>
+ <!--
+ define all your needed colors here
+ -->
+ <colors>
+ <color name="clrRed">FFFF0000</color>
+ <color name="clrGreen">FF5FE200</color>
+ <color name="clrYellow">FFE2DA00</color>
+ <color name="clrBlue">FF007FE2</color>
+ <color name="clrWhite">FFFFFFFF</color>
+ <color name="clrTransWhite">99FFFFFF</color>
+ <color name="clrBlack">FF000000</color>
+ <color name="clrBrightGreen">FF8EAB21</color>
+ <color name="clrDarkGreen">FF4C5C11</color>
+ <color name="clrGray">FF858585</color>
+ <color name="clrDarkBlue">B012273F</color>
+ <color name="clrTransBlack">99000000</color>
+ <color name="clrTransRed">99FF0000</color>
+ <color name="clrFontMenuItem">FFFFFFFF</color>
+ <color name="clrFontMenuItemSelected">FF363636</color>
+ <color name="clrFontInactive">FF858585</color>
+ <color name="clrTransparent">00000000</color>
+ </colors>
+ <!--
+ these variables can be used everywhere in the templates
+ variabls of type int can also be used as conditions, just
+ set such a variable to 1 for true and 0 for false
+ -->
+ <variables>
+ <var type="int" name="fadeTime">300</var>
+ </variables>
+ <!--
+ translations used in the skin
+ -->
+ <translations>
+ <token name="tr(free)">
+ <trans lang="en_EN">free</trans>
+ <trans lang="de_DE">frei</trans>
+ </token>
+ <token name="tr(transponder)">
+ <trans lang="en_EN">Transponder</trans>
+ <trans lang="de_DE">Transponder</trans>
+ </token>
+ <token name="tr(now)">
+ <trans lang="en_EN">Now</trans>
+ <trans lang="de_DE">Jetzt</trans>
+ </token>
+ <token name="tr(next)">
+ <trans lang="en_EN">Next</trans>
+ <trans lang="de_DE">Nachfolgend</trans>
+ </token>
+ <token name="tr(nextschedules)">
+ <trans lang="en_EN">Next Schedules</trans>
+ <trans lang="de_DE">Nachfolgende Sendungen</trans>
+ </token>
+ <token name="tr(reruns)">
+ <trans lang="en_EN">Reruns</trans>
+ <trans lang="de_DE">Wiederholungen</trans>
+ </token>
+ <token name="tr(rerunsof)">
+ <trans lang="en_EN">Reruns of</trans>
+ <trans lang="de_DE">Wiederholungen von</trans>
+ </token>
+ <token name="tr(actors)">
+ <trans lang="en_EN">Actors</trans>
+ <trans lang="de_DE">Schauspieler</trans>
+ </token>
+ <token name="tr(episode)">
+ <trans lang="en_EN">Episode</trans>
+ <trans lang="de_DE">Folge</trans>
+ </token>
+ <token name="tr(season)">
+ <trans lang="en_EN">Season</trans>
+ <trans lang="de_DE">Staffel</trans>
+ </token>
+ <token name="tr(gueststars)">
+ <trans lang="en_EN">Guest Stars</trans>
+ <trans lang="de_DE">Gaststars</trans>
+ </token>
+ <token name="tr(seriesfirstaired)">
+ <trans lang="en_EN">Series First Aired</trans>
+ <trans lang="de_DE">Erstausstrahlung der Serie</trans>
+ </token>
+ <token name="tr(episodefirstaired)">
+ <trans lang="en_EN">Episode First Aired</trans>
+ <trans lang="de_DE">Erstausstrahlung der Episode</trans>
+ </token>
+ <token name="tr(network)">
+ <trans lang="en_EN">Network</trans>
+ <trans lang="de_DE">TV Station</trans>
+ </token>
+ <token name="tr(genre)">
+ <trans lang="en_EN">Genre</trans>
+ <trans lang="de_DE">Genre</trans>
+ </token>
+ <token name="tr(status)">
+ <trans lang="en_EN">Status</trans>
+ <trans lang="de_DE">Status</trans>
+ </token>
+ <token name="tr(rating)">
+ <trans lang="en_EN">Rating</trans>
+ <trans lang="de_DE">Bewertung</trans>
+ </token>
+ <token name="tr(episoderating)">
+ <trans lang="en_EN">Episode Rating</trans>
+ <trans lang="de_DE">Bewertung der Folge</trans>
+ </token>
+ <token name="tr(recinfo)">
+ <trans lang="en_EN">Recording Information</trans>
+ <trans lang="de_DE">Aufnahme Informationen</trans>
+ </token>
+ <token name="tr(seriesgalery)">
+ <trans lang="en_EN">Series Galery</trans>
+ <trans lang="de_DE">Serien Galerie</trans>
+ </token>
+ <token name="tr(moviegalery)">
+ <trans lang="en_EN">Movie Galery</trans>
+ <trans lang="de_DE">Spielfilm Galerie</trans>
+ </token>
+ <token name="tr(originaltitle)">
+ <trans lang="en_EN">Original Title</trans>
+ <trans lang="de_DE">Originaltitel</trans>
+ </token>
+ <token name="tr(budget)">
+ <trans lang="en_EN">Budget</trans>
+ <trans lang="de_DE">Budget</trans>
+ </token>
+ <token name="tr(revenue)">
+ <trans lang="en_EN">Revenue</trans>
+ <trans lang="de_DE">Einnahmen</trans>
+ </token>
+ <token name="tr(adult)">
+ <trans lang="en_EN">Adult</trans>
+ <trans lang="de_DE">Nur für Erwachsene</trans>
+ </token>
+ <token name="tr(releasedate)">
+ <trans lang="en_EN">Release Date</trans>
+ <trans lang="de_DE">Erscheinungsdatum</trans>
+ </token>
+ <token name="tr(runtime)">
+ <trans lang="en_EN">Runtime</trans>
+ <trans lang="de_DE">Laufzeit</trans>
+ </token>
+ <token name="tr(popularity)">
+ <trans lang="en_EN">Popularity</trans>
+ <trans lang="de_DE">Popularität</trans>
+ </token>
+ <token name="tr(voteaverage)">
+ <trans lang="en_EN">Vote Average</trans>
+ <trans lang="de_DE">Durchschnittliche Wertung</trans>
+ </token>
+ <token name="tr(homepage)">
+ <trans lang="en_EN">Homepage</trans>
+ <trans lang="de_DE">Homepage</trans>
+ </token>
+ <token name="tr(recsize)">
+ <trans lang="en_EN">Recording size</trans>
+ <trans lang="de_DE">Größe der Aufnahme</trans>
+ </token>
+ <token name="tr(recsizecutted)">
+ <trans lang="en_EN">Cutted Recording Size</trans>
+ <trans lang="de_DE">Größe der geschnittenen Aufnahme</trans>
+ </token>
+ <token name="tr(reclength)">
+ <trans lang="en_EN">Recording Length</trans>
+ <trans lang="de_DE">Länge der Aufnahme</trans>
+ </token>
+ <token name="tr(reclengthcutted)">
+ <trans lang="en_EN">Cutted Recording Length</trans>
+ <trans lang="de_DE">Länge der geschnittenen Aufnahme</trans>
+ </token>
+ <token name="tr(bitrate)">
+ <trans lang="en_EN">Bit Rate</trans>
+ <trans lang="de_DE">Bitrate</trans>
+ </token>
+ <token name="tr(format)">
+ <trans lang="en_EN">Format</trans>
+ <trans lang="de_DE">Format</trans>
+ </token>
+ <token name="tr(searchtimer)">
+ <trans lang="en_EN">Searchtimer</trans>
+ <trans lang="de_DE">Suchtimer</trans>
+ </token>
+ <token name="tr(volume)">
+ <trans lang="en_EN">Volume</trans>
+ <trans lang="de_DE">Lautstärke</trans>
+ </token>
+ </translations>
+ <!--
+ The three Fonts FontOSD, FontFix and FontSml configured in VDR
+ can be used in all template "font" attributes with this tokens:
+ {vdrOsd}
+ {vdrFix}
+ {vdrSml}
+ If you like to use further fonts, just define them below.
+ Syntax:
+ <font name="tokenname">fontname</font>
+ These fonts can then also be used in all templates in the "font"
+ attribute.
+ if an invalid font is used in a template, vdrOsd is used as default.
+ -->
+ <fonts>
+ </fonts>
+</globals>
diff --git a/skinskeleton/xmlfiles/displayaudiotracks.xml b/skinskeleton/xmlfiles/displayaudiotracks.xml
new file mode 100644
index 0000000..a088d97
--- /dev/null
+++ b/skinskeleton/xmlfiles/displayaudiotracks.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displayaudiotracks SYSTEM "../../dtd/displayaudiotracks.dtd">
+
+<displayaudiotracks x="0" y="0" width="100%" height="100%" fadetime="0">
+ <!-- Available Variables background:
+ {numtracks} number of displayed tracks
+ -->
+ <background>
+ </background>
+
+ <!-- Available Variables header:
+ {numtracks} number of displayed tracks
+ {title} title of menu
+ -->
+ <header>
+ </header>
+
+ <!-- Available Variables header:
+ {numelements} number of displayed tracks
+ -->
+ <menuitems x="0" y="{areaheight} - {numelements} * {areaheight} / 10" orientation="vertical" width="100%" height="{numelements} * {areaheight} / 10" align="top" numlistelements="{numelements}">
+ <!-- Available Variables auidotrack listelement:
+ {current} true if item is currently selected
+ {title} title of auio track
+ -->
+ <listelement>
+ </listelement>
+ </menuitems>
+
+</displayaudiotracks>
diff --git a/skinskeleton/xmlfiles/displaychannel.xml b/skinskeleton/xmlfiles/displaychannel.xml
new file mode 100644
index 0000000..7f55232
--- /dev/null
+++ b/skinskeleton/xmlfiles/displaychannel.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displaychannel SYSTEM "../../dtd/displaychannel.dtd">
+
+<displaychannel x="0" y="0" width="100%" height="100%" fadetime="0">
+
+ <background>
+ </background>
+
+ <!-- Available Variables channelinfo:
+ {channelnumber} Number of Channel, with "-" in case of channel switching
+ {channelname} Name of current Channel
+ {channellogoexists} true if a channel logo exists
+ {channelid} ChannelID as path to display channel logo
+ {switching} true if a number is pressed on the remote to switch to a dedicated channel
+ -->
+ <channelinfo>
+ </channelinfo>
+
+ <!-- Available Variables epginfo:
+ {currenttitle} Title of the current Schedule
+ {currentsubtitle} Subtitle of the current Schedule
+ {currentstart} Start of current Schedule in hh:mm
+ {currentstop} End of current Schedule in hh:mm
+ {currentduration} Duration of current Schedule in min
+ {currentelapsed} Elapsed time of current Schedule in min
+ {currentremaining} Remaining time of current Schedule in min
+ {currentrecording} true if current Schedule is recorded
+ {nexttitle} Title of next Schedule
+ {nextsubtitle} Subtitle of next Schedule
+ {nextstart} Start of next Schedule in hh:mm
+ {nextstop} Stop of next Schedule in hh:mm
+ {nextduration} Duration of next Schedule in min
+ {nextrecording} true if next Schedule will be recorded
+ -->
+ <epginfo>
+ </epginfo>
+
+ <!-- Available Variables progressbar:
+ {start} Start of current Schedule in hh:mm
+ {stop} End of current Schedule in hh:mm
+ {duration} Total Duration of current Schedule in seconds
+ {elapsed} Elapsed time of current Schedule in seconds
+ {remaining} Remaining time of current Schedule in seconds
+ -->
+ <progressbar>
+ </progressbar>
+
+ <!-- Available Variables statusinfo:
+ {isRadio} true if channel is a radio channel
+ {hasVT} true if channel has video text
+ {isStereo} true if a stereo audio trac is available
+ {isDolby} true if a dolby audio track is available
+ {isEncrypted} true if channel is encrypted
+ {isRecording} true if currently a recording is running on this channel
+ -->
+ <statusinfo>
+ </statusinfo>
+
+ <!-- Available Variables screenresolution:
+ {screenwidth} width of currently displayed channel in px
+ {screenheight} height of currently displayed channel in px
+ {resolution} resolution: hd1080i, hd720p, sd576i
+ {aspect} screen aspect, each 4:3, 16:9 or 21:9
+ {isHD} true for hd1080i and hd720p
+ {isWideScreen} true if aspect is 16:9 or 21:9
+ -->
+ <screenresolution>
+ </screenresolution>
+
+ <!-- Available Variables dvbdeviceinfo:
+ {prevAvailable} true if previous Channel Group is avaialble
+ {nextAvailable} true if next Channel Group is avaialble
+ {group} Name of current Channel Group
+ {nextgroup} Name of next Channel Group
+ {prevgroup} Name of prev Channel Group
+ {sepexists} true if a channel separator logo exists
+ {seppath} path for separator logo to use in imagetype "seplogo"
+ -->
+ <channelgroup>
+ </channelgroup>
+
+ <!-- Available Variables signalquality:
+ {signalstrength} STR value of currently displayed channel
+ {signalquality} SNR value of currently displayed channel
+ -->
+ <signalquality>
+ </signalquality>
+
+ <!-- background of signalmeter, will only be drawn if signalquality was deleted -->
+ <signalqualityback>
+ </signalqualityback>
+
+ <!-- Available Variables scrapercontent:
+ {mediapath} Full Path of Poster or Banner to use in image path attribute
+ {mediawidth} width of image in pixel
+ {mediaheight} height of image in pixel
+ {isbanner} true if image is a banner, false if it is a poster
+ -->
+ <scrapercontent>
+ </scrapercontent>
+
+ <!-- Available Variables datetime:
+ {time} time in hh:mm
+ {day} day in digits
+ {dayleadingzero} day in digits with leading 0
+ {dayname} Full name of the day
+ {daynameshort} Short 3 char name of the day
+ {month} month in digits with leading 0
+ {monthname} Full name of the month
+ {monthnameshort} 3 letter abbrivation of month name
+ {year} year in yyyy
+ -->
+ <datetime>
+ </datetime>
+
+ <!-- Available Variables message:
+ {text} message text
+ {status} true if message is a status message
+ {info} true if message is a info message
+ {warning} true if message is a warn message
+ {error} true if message is a error message
+ -->
+ <message>
+ </message>
+
+</displaychannel>
diff --git a/skinskeleton/xmlfiles/displaymenu.xml b/skinskeleton/xmlfiles/displaymenu.xml
new file mode 100644
index 0000000..28d18ee
--- /dev/null
+++ b/skinskeleton/xmlfiles/displaymenu.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displaymenu SYSTEM "../../dtd/displaymenu.dtd" [
+<!ENTITY displaymenudefault SYSTEM "displaymenudefault.xml">
+<!ENTITY displaymenumain SYSTEM "displaymenumain.xml">
+<!ENTITY displaymenusetup SYSTEM "displaymenusetup.xml">
+<!ENTITY displaymenuschedules SYSTEM "displaymenuschedules.xml">
+<!ENTITY displaymenutimers SYSTEM "displaymenutimers.xml">
+<!ENTITY displaymenuchannels SYSTEM "displaymenuchannels.xml">
+<!ENTITY displaymenurecordings SYSTEM "displaymenurecordings.xml">
+<!ENTITY displaymenudetailepg SYSTEM "displaymenudetailepg.xml">
+<!ENTITY displaymenudetailrecording SYSTEM "displaymenudetailrecording.xml">
+<!ENTITY displaymenudetailtext SYSTEM "displaymenudetailtext.xml">
+]>
+
+<displaymenu x="0" y="0" width="100%" height="100%" fadetime="0">
+ <!--
+ The following background, header, datetime and colorbuttons definitions are default
+ implementations. If one or more of these elements are not implemented in the subview,
+ the default implementations are used.
+ -->
+ <background>
+ </background>
+ <!-- Available Variables header:
+ {title} title of current menu
+ {vdrversion} running VDR Version
+ {hasicon} true if a menu icon is available
+ {icon} path of menu icon
+ -->
+ <header>
+ </header>
+ <!-- Available Variables datetime:
+ {time} time in hh:mm
+ {day} day in digits
+ {dayleadingzero} day in digits with leading 0
+ {dayname} Full name of the day
+ {daynameshort} Short 3 char name of the day
+ {month} month in digits with leading 0
+ {monthname} Full name of the month
+ {monthnameshort} 3 letter abbrivation of month name
+ {year} year in yyyy
+ -->
+ <datetime>
+ </datetime>
+ <!-- Available Variables message:
+ {text} message text
+ {status} true if message is an status message
+ {info} true if message is an info message
+ {warning} true if message is an warn message
+ {error} true if message is an error message
+ -->
+ <message>
+ </message>
+ <!-- Available Variables colorbuttons:
+ {red1} true if red button is button 1
+ {red2} true if red button is button 2
+ {red3} true if red button is button 3
+ {red4} true if red button is button 4
+ {green1} true if green button is button 1
+ {green2} true if green button is button 2
+ {green3} true if green button is button 3
+ {green4} true if green button is button 4
+ {yellow1} true if yellow button is button 1
+ {yellow2} true if yellow button is button 2
+ {yellow3} true if yellow button is button 3
+ {yellow4} true if yellow button is button 4
+ {blue1} true if blue button is button 1
+ {blue2} true if blue button is button 2
+ {blue3} true if blue button is button 3
+ {blue4} true if blue button is button 4
+ {red} label of red button
+ {green} label of green button
+ {yellow} label of yellow button
+ {blue} label of blue button
+ -->
+ <colorbuttons>
+ </colorbuttons>
+ &displaymenudefault;
+ &displaymenumain;
+ &displaymenusetup;
+ &displaymenuschedules;
+ &displaymenutimers;
+ &displaymenuchannels;
+ &displaymenurecordings;
+ &displaymenudetailepg;
+ &displaymenudetailrecording;
+ &displaymenudetailtext;
+</displaymenu>
diff --git a/skinskeleton/xmlfiles/displaymenuchannels.xml b/skinskeleton/xmlfiles/displaymenuchannels.xml
new file mode 100644
index 0000000..242a754
--- /dev/null
+++ b/skinskeleton/xmlfiles/displaymenuchannels.xml
@@ -0,0 +1,74 @@
+<menuchannels x="0" y="0" width="100%" height="100%" fadetime="0">
+ <menuitems x="0" y="0" orientation="vertical" width="100%" height="100%" align="center" numlistelements="16">
+ <!-- Available Variables channels menu listelement:
+ {number} number of the displayed channel
+ {name} name of the displayed channel
+ {channelid} ChannelID as path to display channel logo
+ {transponder} Transponder of channel
+ {frequency} Frequency of channel
+ {source} Source of channel (S, C, T)
+ {sourcedescription} Descriptin of source from sources.conf
+ {position} orbital position of the satellite in case this is a DVB-S source
+ {isAtsc} true if channel is a ATSC channel
+ {isCable} true if channel is cable channel
+ {isSat} true if channel is a satellite channel
+ {isTerr} true if channel is terrestrical
+ {presenteventtitle} title of present event on this channel
+ {presenteventstart} present event start time in hh::mm
+ {presenteventstop} present event event stop time in hh::mm
+ {current} true if item is currently selected
+ {separator} true if item is a list separator
+ -->
+ <listelement>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables channels menu currentelement:
+ {menuitemx} x position of according menu item
+ {menuitemy} y position of according menu item
+ {menuitemwidth} width of according menu item
+ {menuitemheight} height of according menu item
+ {number} number of the displayed channel
+ {name} name of the displayed channel
+ {channelid} ChannelID as path to display channel logo
+ {transponder} Transponder of channel
+ {frequency} Frequency of channel
+ {source} Source of channel (S, C, T)
+ {sourcedescription} Descriptin of source from sources.conf
+ {position} orbital position of the satellite in case this is a DVB-S source
+ {isAtsc} true if channel is a ATSC channel
+ {isCable} true if channel is cable channel
+ {isSat} true if channel is a satellite channel
+ {isTerr} true if channel is terrestrical
+ {presenteventtitle} title of present event on this channel
+ {presenteventstart} present event start time in hh::mm
+ {presenteventstop} present event stop time in hh::mm
+ {presenteventshorttext} present event short text
+ {presenteventdescription} present event description
+ {presenteventday} present event name of day
+ {presenteventdate} present event date in dd:mm:yy
+ {presenteventelapsed} present event elapsed time
+ {presenteventduration} present event duration
+ {hasposter} true if a scraped poster is available for this elements present evemt
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {nexteventtitle} title of next event on this channel
+ {nexteventstart} next event start time in hh::mm
+ {nexteventstop} next event event stop time in hh::mm
+ {nexteventshorttext} next event short text
+ {nexteventdescription} next event description
+ {nexteventday} next event name of day
+ {nexteventdate} next event date in dd:mm:yy
+ {nexteventdate} next event duration
+ {schedule[]} array with following 10 schedules
+ {schedule[title]} title of event
+ {schedule[shorttext]} shorttext of event
+ {schedule[start]} start time of event in hh:mm
+ {schedule[stop]} stop time of event in hh:mm
+ -->
+ <currentelement delay="500" fadetime="0">
+ </currentelement>
+
+ </menuitems>
+
+</menuchannels> \ No newline at end of file
diff --git a/skinskeleton/xmlfiles/displaymenudefault.xml b/skinskeleton/xmlfiles/displaymenudefault.xml
new file mode 100644
index 0000000..aed2738
--- /dev/null
+++ b/skinskeleton/xmlfiles/displaymenudefault.xml
@@ -0,0 +1,36 @@
+ <menudefault x="0" y="0" width="100%" height="100%" fadetime="0">
+ <!-- IMPORTANT: menuitemwidth and determinatefont have to be defined here. menuitemwidth defines the total width of the
+ default menu items, determinatefont the function which sets the actual font to use. With that it is possible to determinate
+ the correct column widths -->
+ <menuitems x="0" y="0" orientation="vertical" width="100%" height="100%" align="center" menuitemwidth="94%" determinatefont="column1" numlistelements="16">
+ <!-- Available Variables default menu listelement:
+ {column1} text of column1
+ {column2} text of column2
+ {column3} text of column3
+ {column4} text of column4
+ {column5} text of column5
+ {column6} text of column6
+ {column2set} true if column2 is used
+ {column3set} true if column3 is used
+ {column4set} true if column4 is used
+ {column5set} true if column5 is used
+ {column6set} true if column6 is used
+ {column2x} proposed x value of column2
+ {column3x} proposed x value of column3
+ {column4x} proposed x value of column4
+ {column5x} proposed x value of column5
+ {column6x} proposed x value of column6
+ {column1width} proposed width of column1
+ {column2width} proposed width of column2
+ {column3width} proposed width of column3
+ {column4width} proposed width of column4
+ {column5width} proposed width of column5
+ {column6width} proposed width of column6
+ {current} true if column is currently selected
+ {separator} true if column is a list separator
+ -->
+ <listelement>
+ </listelement>
+
+ </menuitems>
+</menudefault>
diff --git a/skinskeleton/xmlfiles/displaymenudetailepg.xml b/skinskeleton/xmlfiles/displaymenudetailepg.xml
new file mode 100644
index 0000000..66d5399
--- /dev/null
+++ b/skinskeleton/xmlfiles/displaymenudetailepg.xml
@@ -0,0 +1,165 @@
+<menudetailedepg x="0" y="0" width="100%" height="100%" fadetime="0">
+ <!-- Available Variables in detailheader elements:
+ {title} title of event
+ {shorttext} shorttext of event
+ {start} event start time in hh::mm
+ {stop} event stop time
+ {day} day of current event
+ {date} date of current event in dd.mm.yy
+ {running} true if event is currently running
+ {elapsed} elapsed time of event, if not running 0
+ {duration} duration of event
+ {channelid} ChannelID as path to display channel logo
+ {ismovie} true if event is scraped as a movie
+ {isseries} true if event is scraped as a series
+ {posteravailable} true if a poster is available
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {banneravailable} true if a banner is available
+ {bannerwidth} width of banner
+ {bannerheight} height of banner
+ {bannerpath} path of banner
+ {epgpicavailable} true if a epg picture is available
+ {epgpicpath} path of epg picture
+ -->
+ <detailheader>
+ </detailheader>
+
+ <!-- Available Variables in tab elements:
+ {title} title of event
+ {shorttext} shorttext of event
+ {description} description of event
+ {start} event start time in hh::mm
+ {stop} event stop time
+ {day} day of current event
+ {date} date of current event in dd.mm.yy
+ {running} true if event is currently running
+ {elapsed} elapsed time of event, if not running 0
+ {duration} duration of event
+ {channelid} ChannelID as path to display channel logo
+ {hasreruns} true if reruns of this event are found
+ {reruns[]} array with reruns
+ {reruns[title]} title of rerun
+ {reruns[shorttext]} shorttext of rerun
+ {reruns[date]} date of rerun in dd:mm
+ {reruns[day]} short dayname of rerun
+ {reruns[start]} start time of rerun in hh:mm
+ {reruns[stop]} stop time of rerun in hh:mm
+ {reruns[channelname]} name of channel on which rerun occurs
+ {reruns[channelnumber]} number of channel on which rerun occurs
+ {reruns[channelid]} id of channel on which rerun occurs to display channel logo
+ {reruns[channellogoexists]} true if channel logo exists
+ {epgpic1avaialble} true if first epg picture is available
+ {epgpic2avaialble} true if first epg picture is available
+ {epgpic3avaialble} true if first epg picture is available
+ {epgpic1path} path of first epg picture
+ {epgpic2path} path of second epg picture
+ {epgpic3path} path of third epg picture
+
+ {ismovie} true if event is scraped as a movie
+ Available variables for movies:
+ {movietitle} movie title from themoviedb
+ {movieoriginalTitle} movie original title from themoviedb
+ {movietagline} movie tagline from themoviedb
+ {movieoverview} movie overview from themoviedb
+ {movieadult} true if movie is rated as adult
+ {moviebudget} movie budget from themoviedb in $
+ {movierevenue} movie revenue from themoviedb in $
+ {moviegenres} movie genres from themoviedb
+ {moviehomepage} movie homepage from themoviedb
+ {moviereleasedate} movie release date from themoviedb
+ {movieruntime} movie runtime from themoviedb
+ {moviepopularity} movie popularity from themoviedb
+ {movievoteaverage} movie vote average from themoviedb
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {fanartwidth} width of scraped fanart
+ {fanartheight} height of scraped fanart
+ {fanartpath} absolute path of scraped fanart
+ {movieiscollection} true if movie is part of a collection
+ {moviecollectionName} name of movie collection
+ {collectionposterwidth} width of scraped collection poster
+ {collectionposterheight} height of scraped collection poster
+ {collectionposterpath} absolute path of scraped collection poster
+ {collectionfanartwidth} width of scraped collection fanart
+ {collectionfanartheight} height of scraped collection fanart
+ {collectionfanartpath} absolute path of scraped collection fanart
+ {actors[]} array with movie actors
+ {actors[name]} real name of actor
+ {actors[role]} actor role
+ {actors[thumb]} absolute path of scraped actor thumb
+ {actors[thumbwidth]} width of scraped actor thumb
+ {actors[thumbheight]} height of scraped actor thumb
+
+ {isseries} true if event is scraped as a series
+ Available variables for series:
+ {seriesname} name of series
+ {seriesoverview} series overview
+ {seriesfirstaired} first aired date
+ {seriesnetwork} network which produces series
+ {seriesgenre} series genre
+ {seriesrating} series thetvdb rating
+ {seriesstatus} status of series (running / finished)
+ {episodetitle} title of episode
+ {episodenumber} number of episode
+ {episodeseason} season of episode
+ {episodefirstaired} first aired date of episode
+ {episodegueststars} guest stars of episode
+ {episodeoverview} episode overview
+ {episoderating} user rating for episode
+ {episodeimagewidth} episode image width
+ {episodeimageheight} episode image height
+ {episodeimagepath} episode image path
+ {seasonposterwidth} episode season poster width
+ {seasonposterheight} episode season poster height
+ {seasonposterpath} episode season poster path
+ {seriesposter1width} width of 1st poster
+ {seriesposter1height} height of 1st poster
+ {seriesposter1path} path of 1st poster
+ {seriesposter2width} width of 2nd poster
+ {seriesposter2height} height of 2nd poster
+ {seriesposter2path} path of 2nd poster
+ {seriesposter3width} width of 3rd poster
+ {seriesposter3height} height of 3rd poster
+ {seriesposter3path} path of 3rd poster
+ {seriesfanart1width} width of 1st fanart
+ {seriesfanart1height} height of 1st fanart
+ {seriesfanart1path} path of 1st fanart
+ {seriesfanart2width} width of 2nd fanart
+ {seriesfanart2height} height of 2nd fanart
+ {seriesfanart2path} path of 2nd fanart
+ {seriesfanart3width} width of 3rd fanart
+ {seriesfanart3height} height of 3rd fanart
+ {seriesfanart3path} path of 3rd fanart
+ {seriesbanner1width} width of 1st banner
+ {seriesbanner1height} height of 1st banner
+ {seriesbanner1path} path of 1st banner
+ {seriesbanner2width} width of 2nd banner
+ {seriesbanner2height} height of 2nd banner
+ {seriesbanner2path} path of 2nd banner
+ {seriesbanner3width} width of 3rd banner
+ {seriesbanner3height} height of 3rd banner
+ {seriesbanner3path} path of 3rd fanart
+ {actors[]} array with movie actors
+ {actors[name]} real name of actor
+ {actors[role]} actor role
+ {actors[thumb]} absolute path of scraped actor thumb
+ {actors[thumbwidth]} width of scraped actor thumb
+ {actors[thumbheight]} height of scraped actor thumb
+ -->
+
+ <!-- a tab is one scrolling area, just position and draw as inside a normal area -->
+ <!-- just define as many tabs as needed -->
+ <tab name="Tab1" x="0" y="0" width="100%" height="100%" layer="2" scrollheight="{areaheight}/4">
+ </tab>
+
+ <!-- Available Variables tablabels:
+ {tabs[]} array with available tab labels
+ {tabs[title]} title of tab
+ {tabs[current]} true if tab is displayed currently
+ -->
+ <tablabels>
+ </tablabels>
+</menudetailedepg> \ No newline at end of file
diff --git a/skinskeleton/xmlfiles/displaymenudetailrecording.xml b/skinskeleton/xmlfiles/displaymenudetailrecording.xml
new file mode 100644
index 0000000..0587e55
--- /dev/null
+++ b/skinskeleton/xmlfiles/displaymenudetailrecording.xml
@@ -0,0 +1,154 @@
+<menudetailedrecording x="0" y="0" width="100%" height="100%" fadetime="0">
+ <!-- Available Variables in detailheader elements:
+ {name} name of recording
+ {shorttext} shorttext of recording
+ {date} date of recording in dd.mm.yy
+ {time} time of current event in hh:mm
+ {duration} real duration of recording in minutes
+ {durationevent} duration of according event in minutes
+ {ismovie} true if event is scraped as a movie
+ {isseries} true if event is scraped as a series
+ {posteravailable} true if a poster is available
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {banneravailable} true if a banner is available
+ {bannerwidth} width of banner
+ {bannerheight} height of banner
+ {bannerpath} path of banner
+ {recimgavailable} true if a recording image is available in the recording path
+ {recimgpath} path of rec image
+ -->
+ <detailheader>
+ </detailheader>
+ <!-- Available Variables in tab elements:
+ {name} title of recording
+ {shorttext} shorttext of recording
+ {description} description of recording
+ {date} date of recording in dd.mm.yy
+ {time} time of recording in hh:mm
+ {duration} real duration of recording in minutes
+ {durationevent} duration of according event in minutes
+
+ {recordingsize} size of recording (automatically in GB / MB)
+ {recordingsizecutted} size of cutted recording (automatically in GB / MB)
+ {recordinglength} length of recording (in hh::mm:ss)
+ {recordinglengthcutted} length of cutted recording (in hh::mm:ss)
+ {recordingbitrate} bitrate of recording (in MBit/s)
+ {recordingformat} format of recording (TS / PS)
+ {searchtimer} name of accordign searchtimer (if available)
+
+ {recimg1avaialble} true if first recording image is available
+ {recimg2avaialble} true if first recording image is available
+ {recimg3avaialble} true if first recording image is available
+ {recimg1path} path of first recording image
+ {recimg2path} path of second recording image
+ {recimg3path} path of third recording image
+
+ {ismovie} true if event is scraped as a movie
+ Available variables for movies:
+ {movietitle} movie title from themoviedb
+ {movieoriginalTitle} movie original title from themoviedb
+ {movietagline} movie tagline from themoviedb
+ {movieoverview} movie overview from themoviedb
+ {movieadult} true if movie is rated as adult
+ {moviebudget} movie budget from themoviedb in $
+ {movierevenue} movie revenue from themoviedb in $
+ {moviegenres} movie genres from themoviedb
+ {moviehomepage} movie homepage from themoviedb
+ {moviereleasedate} movie release date from themoviedb
+ {movieruntime} movie runtime from themoviedb
+ {moviepopularity} movie popularity from themoviedb
+ {movievoteaverage} movie vote average from themoviedb
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {fanartwidth} width of scraped fanart
+ {fanartheight} height of scraped fanart
+ {fanartpath} absolute path of scraped fanart
+ {movieiscollection} true if movie is part of a collection
+ {moviecollectionName} name of movie collection
+ {collectionposterwidth} width of scraped collection poster
+ {collectionposterheight} height of scraped collection poster
+ {collectionposterpath} absolute path of scraped collection poster
+ {collectionfanartwidth} width of scraped collection fanart
+ {collectionfanartheight} height of scraped collection fanart
+ {collectionfanartpath} absolute path of scraped collection fanart
+ {actors[]} array with movie actors
+ {actors[name]} real name of actor
+ {actors[role]} actor role
+ {actors[thumb]} absolute path of scraped actor thumb
+ {actors[thumbwidth]} width of scraped actor thumb
+ {actors[thumbheight]} height of scraped actor thumb
+
+ {isseries} true if event is scraped as a series
+ Available variables for series:
+ {seriesname} name of series
+ {seriesoverview} series overview
+ {seriesfirstaired} first aired date
+ {seriesnetwork} network which produces series
+ {seriesgenre} series genre
+ {seriesrating} series thetvdb rating
+ {seriesstatus} status of series (running / finished)
+ {episodetitle} title of episode
+ {episodenumber} number of episode
+ {episodeseason} season of episode
+ {episodefirstaired} first aired date of episode
+ {episodegueststars} guest stars of episode
+ {episodeoverview} episode overview
+ {episoderating} user rating for episode
+ {episodeimagewidth} episode image width
+ {episodeimageheight} episode image height
+ {episodeimagepath} episode image path
+ {seasonposterwidth} episode season poster width
+ {seasonposterheight} episode season poster height
+ {seasonposterpath} episode season poster path
+ {seriesposter1width} width of 1st poster
+ {seriesposter1height} height of 1st poster
+ {seriesposter1path} path of 1st poster
+ {seriesposter2width} width of 2nd poster
+ {seriesposter2height} height of 2nd poster
+ {seriesposter2path} path of 2nd poster
+ {seriesposter3width} width of 3rd poster
+ {seriesposter3height} height of 3rd poster
+ {seriesposter3path} path of 3rd poster
+ {seriesfanart1width} width of 1st fanart
+ {seriesfanart1height} height of 1st fanart
+ {seriesfanart1path} path of 1st fanart
+ {seriesfanart2width} width of 2nd fanart
+ {seriesfanart2height} height of 2nd fanart
+ {seriesfanart2path} path of 2nd fanart
+ {seriesfanart3width} width of 3rd fanart
+ {seriesfanart3height} height of 3rd fanart
+ {seriesfanart3path} path of 3rd fanart
+ {seriesbanner1width} width of 1st banner
+ {seriesbanner1height} height of 1st banner
+ {seriesbanner1path} path of 1st banner
+ {seriesbanner2width} width of 2nd banner
+ {seriesbanner2height} height of 2nd banner
+ {seriesbanner2path} path of 2nd banner
+ {seriesbanner3width} width of 3rd banner
+ {seriesbanner3height} height of 3rd banner
+ {seriesbanner3path} path of 3rd fanart
+ {actors[]} array with movie actors
+ {actors[name]} real name of actor
+ {actors[role]} actor role
+ {actors[thumb]} absolute path of scraped actor thumb
+ {actors[thumbwidth]} width of scraped actor thumb
+ {actors[thumbheight]} height of scraped actor thumb
+ -->
+
+ <!-- a tab is one scrolling area, just position and draw as inside a normal area -->
+ <!-- just define as many tabs as needed -->
+ <tab name="Tab1" x="0" y="0" width="100%" height="100%" layer="2" scrollheight="{areaheight}/4">
+ </tab>
+
+ <!-- Available Variables tablabels:
+ {tabs[]} array with available tab labels
+ {tabs[title]} title of tab
+ {tabs[current]} true if tab is displayed currently
+ -->
+ <tablabels>
+ </tablabels>
+
+</menudetailedrecording>
diff --git a/skinskeleton/xmlfiles/displaymenudetailtext.xml b/skinskeleton/xmlfiles/displaymenudetailtext.xml
new file mode 100644
index 0000000..6c91e5d
--- /dev/null
+++ b/skinskeleton/xmlfiles/displaymenudetailtext.xml
@@ -0,0 +1,9 @@
+<menudetailedtext x="0" y="0" width="100%" height="100%" fadetime="0">
+
+ <!-- Available Variables in tab elements:
+ {text} detailed text
+ -->
+ <tab name="text" x="0" y="0" width="100" height="100%" layer="1" scrollheight="{areaheight}/4">
+ </tab>
+
+</menudetailedtext> \ No newline at end of file
diff --git a/skinskeleton/xmlfiles/displaymenumain.xml b/skinskeleton/xmlfiles/displaymenumain.xml
new file mode 100644
index 0000000..98c108a
--- /dev/null
+++ b/skinskeleton/xmlfiles/displaymenumain.xml
@@ -0,0 +1,79 @@
+<menumain x="0" y="0" width="100%" height="100%" fadetime="0">
+
+ <!-- Available Variables timers:
+ {numtimers} number of active timers (max. 15 timers will be displayed)
+ {numtimerconflicts} number of current timer conflicts
+ {timer1exists} true if timer 1 available
+ {timer2exists} true if timer 2 available
+ ...
+ {timer15exists} true if timer 15 available
+ {timers[]} array with active timers (local and remote if remotetimers plugin is in use)
+ {timers[title]} title of timer
+ {timers[datetime]} date and time of timer
+ {timers[recording]} true if timer is recording currently
+ {timers[channelname]} name of channel for which timer is created
+ {timers[channelnumber]} number of channel
+ {timers[channelid]} ChannelID of channel
+ {timers[channellogoexists]} true if channel logo exists
+ -->
+ <timers>
+ </timers>
+
+ <!-- Available Variables discusage:
+ {freetime} available disc capacity in hh:mm
+ {freepercent} available disc capacity in percent
+ {usedpercent} used disc capacity in percent
+ {freegb} available disc capacity in gigabytes
+ {discalert} true if disc usage is > 95%
+ {vdrusagestring} localized VDR internal usage string
+ -->
+ <discusage>
+ </discusage>
+
+ <!-- Available Variables devices:
+ {numdevices} number of available devices
+ {devices[]} array with available devices
+ {devices[num]} number of current device
+ {devices[type]} type of device (DVB-S, DVB-C, ...)
+ {devices[istuned]} true if device is currently tuned to a transponder
+ {devices[livetv]} true if device is currently playing livetv
+ {devices[recording]} true if device is currently recording
+ {devices[hascam]} true if device has a CAM
+ {devices[cam]} number of CAM
+ {devices[signalstrength]} signalstrength of devcie
+ {devices[signalquality]} signalstrength of devcie
+ {devices[channelnumber]} number of the currently tuned channel
+ {devices[channelname]} name of the currently tuned channel
+ {devices[channelid]} ID of the currently tuned channel
+ {devices[source]} source of the currently tuned channel
+ -->
+ <devices>
+ </devices>
+
+ <!-- Available Variables systemload:
+ {load} current system load
+ -->
+ <systemload>
+ </systemload>
+
+ <menuitems x="0" y="0" orientation="vertical" width="100%" height="100%" align="center" numlistelements="8">
+ <!-- Available Variables main menu listelement:
+ {label} label of menu item
+ {number} number of menu item (or empty string if not set)
+ {icon} path of appropriate icon
+ {current} true if item is currently selected
+ {separator} true if item is a list separator
+ -->
+ <listelement>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables main menu currentelement:
+ {label} label of menu item
+ {number} number of menu item (or empty string if not set)
+ {icon} path of appropriate icon
+ -->
+ <currentelement delay="50" fadetime="0">
+ </currentelement>
+ </menuitems>
+
+</menumain>
diff --git a/skinskeleton/xmlfiles/displaymenurecordings.xml b/skinskeleton/xmlfiles/displaymenurecordings.xml
new file mode 100644
index 0000000..ca4023d
--- /dev/null
+++ b/skinskeleton/xmlfiles/displaymenurecordings.xml
@@ -0,0 +1,49 @@
+<menurecordings x="0" y="0" width="100%" height="100%" fadetime="0">
+ <menuitems x="0" y="0" orientation="vertical" width="100%" height="100%" align="center" numlistelements="16">
+ <!-- Available Variables recordings menu listelement:
+ {name} Name of recording
+ {date} Date of recording
+ {time} Time of recording
+ {duration} real duration of recording in minutes
+ {durationevent} duration of corresponding event in minutes
+ {current} true if item is currently selected
+ {new} true if recording is new
+ {cutted} true if recording is cutted
+ {folder} true if item is a folder
+ {numrecordingsfolder} if item is a folder, number of recordings in this folder
+ {newrecordingsfolder} if item is a folder, number of new recordings in this folder
+ {hasposterthumbnail} true if a scraped poster thumbnail is available for recording
+ {thumbnailbwidth} width of scraped poster thumbnail
+ {thumbnailheight} height of scraped poster thumbnail
+ {thumbnailpath} absolute path of scraped poster thumbnail
+ -->
+ <listelement>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables channels menu currentelement:
+ {menuitemx} x position of according menu item
+ {menuitemy} y position of according menu item
+ {menuitemwidth} width of according menu item
+ {menuitemheight} height of according menu item
+ {name} Name of recording
+ {shorttext} Short Text of recording
+ {description} Descrption of recording
+ {date} Date of recording
+ {time} Time of recording
+ {duration} real duration of recording in minutes
+ {durationevent} duration of corresponding event in minutes
+ {new} true if recording is new
+ {cutted} true if recording is cutted
+ {folder} true if item is a folder
+ {numrecordingsfolder} if item is a folder, number of recordings in this folder
+ {newrecordingsfolder} if item is a folder, number of new recordings in this folder
+ {hasposter} true if a scraped poster is available for recording
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ -->
+ <currentelement delay="500" fadetime="0">
+ </currentelement>
+ </menuitems>
+
+</menurecordings> \ No newline at end of file
diff --git a/skinskeleton/xmlfiles/displaymenuschedules.xml b/skinskeleton/xmlfiles/displaymenuschedules.xml
new file mode 100644
index 0000000..3c615c9
--- /dev/null
+++ b/skinskeleton/xmlfiles/displaymenuschedules.xml
@@ -0,0 +1,73 @@
+<menuschedules x="0" y="0" width="100%" height="100%" fadetime="0">
+ <!-- Available Variables header:
+ {title} title of current menu
+ {vdrversion} running VDR Version
+ {channelnumber} Number of Channel of current event
+ {channelname} Name of current Channel of current event
+ {channellogoexists} true if a channel logo exists
+ {channelid} ChannelID as path to display channel logo
+ {whatson} true if menu "What's on" is displayed
+ {whatsonnow} true if menu "What's on now" is displayed
+ {whatsonnext} true if menu "What's on next" is displayed
+ -->
+ <header>
+ </header>
+
+ <menuitems x="0" y="0" orientation="vertical" width="100%" height="100%" align="center" numlistelements="16">
+ <!-- Available Variables schedules menu listelement:
+ {title} title of event
+ {shorttext} shorttext of event
+ {start} event start time in hh::mm
+ {stop} event stop time
+ {day} day of current event
+ {date} date of current event in dd.mm.yy
+ {running} true if event is currently running
+ {elapsed} elapsed time of event, if not running 0
+ {duration} duration of event
+ {current} true if item is currently selected
+ {separator} true if item is a list separator
+ {channelid} ChannelID as path to display channel logo
+ {whatson} true if menu "What's on" is displayed
+ {whatsonnow} true if menu "What's on now" is displayed
+ {whatsonnext} true if menu "What's on next" is displayed
+ {timerpartitial} true if partitial timer is set for the event
+ {timerfull} true if full timer is set for the event
+ -->
+ <listelement>
+ </listelement>
+ <!-- Available Variables schedules menu currentelement:
+ {menuitemx} x position of according menu item
+ {menuitemy} y position of according menu item
+ {menuitemwidth} width of according menu item
+ {menuitemheight} height of according menu item
+ {title} title of event
+ {shorttext} shorttext of event
+ {description} detailed description of event
+ {start} event start time in hh::mm
+ {stop} event stop time
+ {day} day of current event
+ {date} date of current event in dd.mm.yy
+ {running} true if event is currently running
+ {elapsed} elapsed time of event, if not running 0
+ {duration} duration of event
+ {channelid} ChannelID as path to display channel logo
+ {hasposter} true if a scraped poster is available for this element
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {timerpartitial} true if partitial timer is set for the event
+ {timerfull} true if full timer is set for the event
+ {whatson} true if menu "What's on" is displayed
+ {whatsonnow} true if menu "What's on now" is displayed
+ {whatsonnext} true if menu "What's on next" is displayed
+ {schedule[]} array with next 10 schedules, only for whatsonnow and whatsonnext
+ {schedule[title]} title of event
+ {schedule[shorttext]} shorttext of event
+ {schedule[start]} start time of event in hh:mm
+ {schedule[stop]} stop time of event in hh:mm
+ -->
+ <currentelement delay="500" fadetime="0">
+ </currentelement>
+ </menuitems>
+
+</menuschedules> \ No newline at end of file
diff --git a/skinskeleton/xmlfiles/displaymenusetup.xml b/skinskeleton/xmlfiles/displaymenusetup.xml
new file mode 100644
index 0000000..fe21641
--- /dev/null
+++ b/skinskeleton/xmlfiles/displaymenusetup.xml
@@ -0,0 +1,27 @@
+<menusetup x="0" y="0" width="100%" height="100%" fadetime="0">
+
+ <menuitems x="0" y="0" orientation="vertical" width="100%" height="100%" align="center" numlistelements="16">
+ <!-- Available Variables setup menu listelement:
+ {label} label of menu item
+ {number} number of menu item (or empty string if not set)
+ {icon} path of appropriate icon
+ {current} true if item is currently selected
+ {separator} true if item is a list separator
+ -->
+ <listelement>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables main menu currentelement:
+ {menuitemx} x position of according menu item
+ {menuitemy} y position of according menu item
+ {menuitemwidth} width of according menu item
+ {menuitemheight} height of according menu item
+ {label} label of menu item
+ {number} number of menu item (or empty string if not set)
+ {icon} path of appropriate icon
+ -->
+ <currentelement delay="50" fadetime="0">
+ </currentelement>
+ </menuitems>
+
+</menusetup>
diff --git a/skinskeleton/xmlfiles/displaymenutimers.xml b/skinskeleton/xmlfiles/displaymenutimers.xml
new file mode 100644
index 0000000..612c23f
--- /dev/null
+++ b/skinskeleton/xmlfiles/displaymenutimers.xml
@@ -0,0 +1,58 @@
+<menutimers x="0" y="0" width="100%" height="100%" fadetime="0">
+ <menuitems x="0" y="0" orientation="vertical" width="100%" height="100%" align="center" numlistelements="16">
+ <!-- Available Variables channels menu listelement:
+ {title} Title of Timer
+ {timerstart} Start Time of Timer in hh::mm
+ {timerstop} End Time of Timer in hh::mm
+ {day} Day (numerical)
+ {dayname} Day, for repeating timers days where timer is active
+ {channelname} Name of channel which is set for the timer
+ {channelid} ID of channel which is set for the timer (for dispalying channel logo)
+ {channelnumber} Number of channel which is set for the timer
+ {eventtitle} Title of corresponding event
+ {eventstart} Start Time of corresponding event in hh::mm
+ {eventstop} Stop Time of corresponding event in hh::mm
+ {current} true if item is currently selected
+ {flagactive} true if timer is active
+ {flaginstant} true if timer is an instant timer
+ {flagvps} true if timer uses VPS
+ {flagrecording} true if is recording currently
+ {flagpending} true if timer is pending
+ -->
+ <listelement>
+ </listelement>
+ <!-- additional element which is drawn for current element -->
+ <!-- Available Variables channels menu currentelement:
+ {menuitemx} x position of according menu item
+ {menuitemy} y position of according menu item
+ {menuitemwidth} width of according menu item
+ {menuitemheight} height of according menu item
+ {title} Title of Timer
+ {timerstart} Start Time of Timer in hh::mm
+ {timerstop} End Time of Timer in hh::mm
+ {day} Day (numerical)
+ {dayname} Day, for repeating timers days where timer is active
+ {channelname} Name of channel which is set for the timer
+ {channelid} ID of channel which is set for the timer (for dispalying channel logo)
+ {channelnumber} Number of channel which is set for the timer
+ {eventtitle} Title of corresponding event
+ {eventstart} Start Time of corresponding event in hh::mm
+ {eventstop} Stop Time of corresponding event in hh::mm
+ {eventshorttext} Short Text corresponding event
+ {eventdescription} Description corresponding event
+ {hasposter} true if a scraped poster is available for event
+ {posterwidth} width of scraped poster
+ {posterheight} height of scraped poster
+ {posterpath} absolute path of scraped poster
+ {flagactive} true if timer is active
+ {flaginstant} true if timer is an instant timer
+ {flagvps} true if timer uses VPS
+ {flagrecording} true if is recording currently
+ {flagpending} true if timer is pending
+ -->
+ <currentelement delay="500" fadetime="0">
+ </currentelement>
+
+ </menuitems>
+
+</menutimers> \ No newline at end of file
diff --git a/skinskeleton/xmlfiles/displaymessage.xml b/skinskeleton/xmlfiles/displaymessage.xml
new file mode 100644
index 0000000..11d2ea6
--- /dev/null
+++ b/skinskeleton/xmlfiles/displaymessage.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displaymessage SYSTEM "../../dtd/displaymessage.dtd">
+
+<displaymessage x="0" y="0" width="100%" height="100%" fadetime="0">
+
+ <background>
+ </background>
+
+ <!-- Available Variables message:
+ {text} message text
+ {status} true if message is a status message
+ {info} true if message is a info message
+ {warning} true if message is a warn message
+ {error} true if message is a error message
+ -->
+ <message>
+ </message>
+
+</displaymessage>
diff --git a/skinskeleton/xmlfiles/displayreplay.xml b/skinskeleton/xmlfiles/displayreplay.xml
new file mode 100644
index 0000000..4f41222
--- /dev/null
+++ b/skinskeleton/xmlfiles/displayreplay.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displayreplay SYSTEM "../../dtd/displayreplay.dtd">
+
+<displayreplay x="0" y="0" width="100%" height="100%" fadetime="0">
+
+ <background>
+ </background>
+
+ <backgroundmodeonly>
+ </backgroundmodeonly>
+
+ <!-- Available Variables datetime:
+ {time} time in hh:mm
+ {day} day in digits
+ {dayleadingzero} day in digits with leading 0
+ {dayname} Full name of the day
+ {daynameshort} Short 3 char name of the day
+ {month} month in digits with leading 0
+ {monthname} Full name of the month
+ {monthnameshort} 3 letter abbrivation of month name
+ {year} year in yyyy
+ -->
+ <datetime>
+ </datetime>
+
+ <!-- Available Variables scrapercontent:
+ {mediapath} Full Path of Poster or Banner to use in image path attribute
+ {mediawidth} width of image in pixel
+ {mediaheight} height of image in pixel
+ {isbanner} true if image is a banner, false if it is a poster
+ -->
+ <scrapercontent>
+ </scrapercontent>
+
+ <!-- Available Variables rectitle:
+ {rectitle} Title of Recording
+ {recsubtitle} Subtitle of the Recording
+ {recdate} Date Recording in dd.mm.yy
+ {rectime} Time of Recording in hh:mm
+ -->
+ <rectitle>
+ </rectitle>
+
+ <!-- Available Variables recinfo:
+ {screenwidth} width of currently displayed recording in px
+ {screenheight} height of currently displayed recording in px
+ {resolution} resolution: hd1080i, hd720p, sd576i
+ {aspect} screen aspect, each 4:3, 16:9 or 21:9
+ {isHD} true for hd1080i and hd720p
+ {isWideScreen} true if aspect is 16:9 or 21:9
+ -->
+ <recinfo>
+ </recinfo>
+
+ <!-- Available Variables currenttime:
+ {reccurrent} Current Time in hh:mm:ss
+ -->
+ <currenttime>
+ </currenttime>
+
+ <!-- Available Variables totaltime:
+ {rectotal} Total Time in hh:mm:ss
+ -->
+ <totaltime>
+ </totaltime>
+
+ <!-- Available Variables progressbar:
+ {current} current frame of recording
+ {total} total frames of recording
+ -->
+ <progressbar>
+ </progressbar>
+
+ <!-- Available Variables cutmarks:
+ {marks[]} array of available marks
+ {marks[position]} frame of current mark
+ {marks[endposition]} frame where startmark ends
+ {marks[total]} total number of frames
+ {marks[startmark]} true if mark is start mark
+ -->
+ <cutmarks>
+ </cutmarks>
+
+ <!-- Available Variables controlicons and controliconsmodeonly:
+ {play} true if recording is played currently
+ {pause} true if recording is paused
+ {forward} true if fast forwarding
+ {forward1x} true if fast forwarding 1x (with 3 trickspeeds)
+ {forward2x} true if fast forwarding 2x (with 3 trickspeeds)
+ {forward3x} true if fast forwarding 3x (with 3 trickspeeds)
+ {rewind} true if rewinding
+ {rewind1x} true if rewinding 1x (with 3 trickspeeds)
+ {rewind2x} true if rewinding 2x (with 3 trickspeeds)
+ {rewind3x} true if rewinding 3x (with 3 trickspeeds)
+ -->
+ <controlicons>
+ </controlicons>
+
+ <controliconsmodeonly>
+ </controliconsmodeonly>
+
+ <!-- Available Variables jump:
+ {jump} time to jump to in hh:mm
+ -->
+ <jump>
+ </jump>
+ <!-- Available Variables message:
+ {text} message text
+ {status} true if message is a status message
+ {info} true if message is a info message
+ {warning} true if message is a warn message
+ {error} true if message is a error message
+ -->
+ <message>
+ </message>
+
+</displayreplay>
diff --git a/skinskeleton/xmlfiles/displayvolume.xml b/skinskeleton/xmlfiles/displayvolume.xml
new file mode 100644
index 0000000..92d4f7c
--- /dev/null
+++ b/skinskeleton/xmlfiles/displayvolume.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE displayvolume SYSTEM "../../dtd/displayvolume.dtd">
+
+<displayvolume x="0" y="0" width="100%" height="100%" fadetime="0">
+
+ <background>
+ </background>
+
+ <!-- Available Variables volume:
+ {volume} current volume, range from 0 to 255
+ {volumepercent} current volume in %
+ {maxvolume} maximal volume
+ {mute} true if volume is muted
+ -->
+ <volume>
+ </volume>
+
+</displayvolume>
diff --git a/skinskeleton/xmlfiles/globals.xml b/skinskeleton/xmlfiles/globals.xml
new file mode 100644
index 0000000..01f37fb
--- /dev/null
+++ b/skinskeleton/xmlfiles/globals.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE globals SYSTEM "../../dtd/globals.dtd">
+
+<globals>
+ <!--
+ define all your needed colors here
+ -->
+ <colors>
+ </colors>
+ <!--
+ these variables can be used everywhere in the templates
+ variabls of type int can also be used as conditions, just
+ set such a variable to 1 for true and 0 for false
+ -->
+ <variables>
+ </variables>
+ <!--
+ translations used in the skin
+ -->
+ <translations>
+ </translations>
+ <!--
+ The three Fonts FontOSD, FontFix and FontSml configured in VDR
+ can be used in all template "font" attributes with this tokens:
+ {vdrOsd}
+ {vdrFix}
+ {vdrSml}
+ If you like to use further fonts, just define them below.
+ Syntax:
+ <font name="tokenname">fontname</font>
+ These fonts can then also be used in all templates in the "font"
+ attribute.
+ if an invalid font is used in a template, vdrOsd is used as default.
+ -->
+ <fonts>
+ </fonts>
+</globals>
diff --git a/themes/skindesigner-default.theme b/themes/skindesigner-default.theme
new file mode 100644
index 0000000..f6da510
--- /dev/null
+++ b/themes/skindesigner-default.theme
@@ -0,0 +1 @@
+Description = MetrixHD
diff --git a/themes/skindesigner-nopacity.theme b/themes/skindesigner-nopacity.theme
new file mode 100644
index 0000000..85dfa81
--- /dev/null
+++ b/themes/skindesigner-nopacity.theme
@@ -0,0 +1 @@
+Description = nOpacity Freestyle
diff --git a/views/displayaudiotracksview.c b/views/displayaudiotracksview.c
new file mode 100644
index 0000000..c4b9f9a
--- /dev/null
+++ b/views/displayaudiotracksview.c
@@ -0,0 +1,79 @@
+#define __STL_CONFIG_H
+#include <vdr/menu.h>
+#include "displayaudiotracksview.h"
+
+cDisplayAudiotracksView::cDisplayAudiotracksView(int numTracks, cTemplateView *tmplView) : cView(tmplView) {
+ DeleteOsdOnExit();
+ SetFadeTime(tmplView->GetNumericParameter(ptFadeTime));
+
+ this->numTracks = numTracks;
+
+ cTemplateViewList *tmplMenuItems = tmplView->GetViewList(vlMenuItem);
+ listView = NULL;
+ if (tmplMenuItems) {
+ listView = new cDisplayMenuListView(tmplMenuItems, numTracks);
+ }
+}
+
+cDisplayAudiotracksView::~cDisplayAudiotracksView() {
+ if (listView)
+ delete listView;
+ CancelSave();
+ FadeOut();
+}
+
+bool cDisplayAudiotracksView::createOsd(void) {
+ cRect osdSize = tmplView->GetOsdSize();
+ bool ok = CreateOsd(cOsd::OsdLeft() + osdSize.X(),
+ cOsd::OsdTop() + osdSize.Y(),
+ osdSize.Width(),
+ osdSize.Height());
+ return ok;
+}
+
+void cDisplayAudiotracksView::DrawBackground(void) {
+ if (!ViewElementImplemented(veBackground)) {
+ return;
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ intTokens.insert(pair<string,int>("numtracks", numTracks));
+
+ DrawViewElement(veBackground, &stringTokens, &intTokens);
+}
+
+void cDisplayAudiotracksView::DrawHeader(const char *title, int audioChannel) {
+ if (!ViewElementImplemented(veHeader)) {
+ return;
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ intTokens.insert(pair<string,int>("numtracks", numTracks));
+ if (audioChannel < 0) {
+ intTokens.insert(pair<string,int>("isac3", true));
+ intTokens.insert(pair<string,int>("isstereo", false));
+ } else {
+ intTokens.insert(pair<string,int>("isac3", false));
+ intTokens.insert(pair<string,int>("isstereo", true));
+ }
+ stringTokens.insert(pair<string,string>("title", title));
+
+ ClearViewElement(veHeader);
+ DrawViewElement(veHeader, &stringTokens, &intTokens);
+}
+
+void cDisplayAudiotracksView::RenderMenuItems(void) {
+ if (listView)
+ listView->Render();
+}
+
+void cDisplayAudiotracksView::Action(void) {
+ SetInitFinished();
+ FadeIn();
+ DoFlush();
+ cView::Action();
+}
diff --git a/views/displayaudiotracksview.h b/views/displayaudiotracksview.h
new file mode 100644
index 0000000..3414d66
--- /dev/null
+++ b/views/displayaudiotracksview.h
@@ -0,0 +1,24 @@
+#ifndef __DISPLAYAUDIOTRACKSVIEW_H
+#define __DISPLAYAUDIOTRACKSVIEW_H
+
+#include "../libtemplate/template.h"
+#include "displaymenulistview.h"
+
+class cDisplayAudiotracksView : public cView {
+protected:
+ int numTracks;
+ cDisplayMenuListView *listView;
+ virtual void Action(void);
+public:
+ cDisplayAudiotracksView(int numTracks, cTemplateView *tmplView);
+ virtual ~cDisplayAudiotracksView();
+ bool createOsd(void);
+ void DrawBackground(void);
+ void DrawHeader(const char *title, int audioChannel);
+ cDisplayMenuListView *GetListView(void) { return listView; };
+ void DoFadeIn(void) { Start(); };
+ void Flush(void) { DoFlush(); };
+ void RenderMenuItems(void);
+};
+
+#endif //__DISPLAYAUDIOTRACKSVIEW_H
diff --git a/views/displaychannelview.c b/views/displaychannelview.c
new file mode 100644
index 0000000..66155a1
--- /dev/null
+++ b/views/displaychannelview.c
@@ -0,0 +1,452 @@
+#define __STL_CONFIG_H
+#include <vdr/menu.h>
+#include "../services/scraper2vdr.h"
+#include "displaychannelview.h"
+#include "../libcore/timers.h"
+#include "../libcore/helpers.h"
+
+
+cDisplayChannelView::cDisplayChannelView(cTemplateView *tmplView) : cView(tmplView) {
+ lastDate = "";
+ lastScreenWidth = 0;
+ lastScreenHeight = 0;
+ lastSignalDisplay = 0;
+ lastSignalStrength = 0;
+ lastSignalQuality = 0;
+ DeleteOsdOnExit();
+ SetFadeTime(tmplView->GetNumericParameter(ptFadeTime));
+}
+
+cDisplayChannelView::~cDisplayChannelView() {
+ CancelSave();
+ FadeOut();
+}
+
+bool cDisplayChannelView::createOsd(void) {
+ cRect osdSize = tmplView->GetOsdSize();
+ bool ok = CreateOsd(cOsd::OsdLeft() + osdSize.X(),
+ cOsd::OsdTop() + osdSize.Y(),
+ osdSize.Width(),
+ osdSize.Height());
+ return ok;
+}
+
+void cDisplayChannelView::DrawBackground(void) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+ DrawViewElement(veBackground, &stringTokens, &intTokens);
+}
+
+void cDisplayChannelView::DrawChannel(cString &number, cString &name, cString &id, bool switching) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ stringTokens.insert(pair<string,string>("channelname", *name));
+ stringTokens.insert(pair<string,string>("channelnumber", *number));
+ stringTokens.insert(pair<string,string>("channelid", *id));
+
+ intTokens.insert(pair<string, int>("switching", switching));
+ bool logoExisis = imgCache->LogoExists(*id);
+ intTokens.insert(pair<string, int>("channellogoexists", logoExisis));
+
+ DrawViewElement(veChannelInfo, &stringTokens, &intTokens);
+}
+
+void cDisplayChannelView::ClearChannel(void) {
+ ClearViewElement(veChannelInfo);
+}
+
+void cDisplayChannelView::DrawDate(void) {
+ if (!ViewElementImplemented(veDateTime)) {
+ return;
+ }
+ cString curDate = DayDateTime();
+ if (strcmp(curDate, lastDate)) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ time_t t = time(0); // get time now
+ struct tm * now = localtime(&t);
+
+ intTokens.insert(pair<string, int>("year", now->tm_year + 1900));
+ intTokens.insert(pair<string, int>("day", now->tm_mday));
+
+ char monthname[20];
+ char monthshort[10];
+ strftime(monthshort, sizeof(monthshort), "%b", now);
+ strftime(monthname, sizeof(monthname), "%B", now);
+
+ stringTokens.insert(pair<string,string>("monthname", monthname));
+ stringTokens.insert(pair<string,string>("monthnameshort", monthshort));
+ stringTokens.insert(pair<string,string>("month", *cString::sprintf("%02d", now->tm_mon + 1)));
+ stringTokens.insert(pair<string,string>("dayleadingzero", *cString::sprintf("%02d", now->tm_mday)));
+ stringTokens.insert(pair<string,string>("dayname", *WeekDayNameFull(now->tm_wday)));
+ stringTokens.insert(pair<string,string>("daynameshort", *WeekDayName(now->tm_wday)));
+ stringTokens.insert(pair<string,string>("time", *TimeString(t)));
+
+ ClearViewElement(veDateTime);
+ DrawViewElement(veDateTime, &stringTokens, &intTokens);
+
+ lastDate = curDate;
+ }
+}
+
+void cDisplayChannelView::DrawProgressBar(cString &start, cString &stop, int Current, int Total) {
+ if (!ViewElementImplemented(veProgressBar)) {
+ return;
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ stringTokens.insert(pair<string, string>("start", *start));
+ stringTokens.insert(pair<string, string>("stop", *stop));
+
+ intTokens.insert(pair<string, int>("duration", Total));
+ intTokens.insert(pair<string, int>("elapsed", Current));
+ intTokens.insert(pair<string, int>("remaining", Total - Current));
+
+ DrawViewElement(veProgressBar, &stringTokens, &intTokens);
+}
+
+void cDisplayChannelView::ClearProgressBar(void) {
+ ClearViewElement(veProgressBar);
+}
+
+void cDisplayChannelView::DrawProgressBarBack(void) {
+ DrawViewElement(veProgressBarBack);
+}
+
+void cDisplayChannelView::ClearProgressBarBack(void) {
+ ClearViewElement(veProgressBarBack);
+}
+
+void cDisplayChannelView::DrawEPGInfo(const cEvent *present, const cEvent *next, bool presentRecording, bool nextRecording) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ if (present) {
+ stringTokens.insert(pair<string,string>("currenttitle", (present->Title())?present->Title():""));
+ stringTokens.insert(pair<string,string>("currentsubtitle", (present->ShortText())?present->ShortText():""));
+ stringTokens.insert(pair<string,string>("currentstart", *present->GetTimeString()));
+ stringTokens.insert(pair<string,string>("currentstop", *present->GetEndTimeString()));
+
+ intTokens.insert(pair<string,int>("currentduration", present->Duration() / 60));
+ intTokens.insert(pair<string,int>("currentelapsed", (int)round((time(NULL) - present->StartTime())/60)));
+ intTokens.insert(pair<string,int>("currentremaining", (int)round((present->EndTime() - time(NULL))/60)));
+ intTokens.insert(pair<string,int>("currentrecording", presentRecording ? 1 : 0));
+ } else {
+ stringTokens.insert(pair<string,string>("currenttitle", ""));
+ stringTokens.insert(pair<string,string>("currentsubtitle", ""));
+ stringTokens.insert(pair<string,string>("currentstart", ""));
+ stringTokens.insert(pair<string,string>("currentstop", ""));
+
+ intTokens.insert(pair<string,int>("currentduration", 0));
+ intTokens.insert(pair<string,int>("currentelapsed", 0));
+ intTokens.insert(pair<string,int>("currentremaining", 0));
+ intTokens.insert(pair<string,int>("currentrecording", 0));
+ }
+
+ if (next) {
+ stringTokens.insert(pair<string,string>("nexttitle", (next->Title())?next->Title():""));
+ stringTokens.insert(pair<string,string>("nextsubtitle", (next->ShortText())?next->ShortText():""));
+ stringTokens.insert(pair<string,string>("nextstart", *next->GetTimeString()));
+ stringTokens.insert(pair<string,string>("nextstop", *next->GetEndTimeString()));
+
+ intTokens.insert(pair<string,int>("nextduration", next->Duration() / 60));
+ intTokens.insert(pair<string,int>("nextrecording", nextRecording ? 1 : 0));
+ } else {
+ stringTokens.insert(pair<string,string>("nexttitle", ""));
+ stringTokens.insert(pair<string,string>("nextsubtitle", ""));
+ stringTokens.insert(pair<string,string>("nextstart", ""));
+ stringTokens.insert(pair<string,string>("nextstop", ""));
+
+ intTokens.insert(pair<string,int>("nextduration", 0));
+ intTokens.insert(pair<string,int>("nextrecording", 0));
+ }
+ DrawViewElement(veEpgInfo, &stringTokens, &intTokens);
+}
+
+void cDisplayChannelView::ClearEPGInfo(void) {
+ ClearViewElement(veEpgInfo);
+}
+
+void cDisplayChannelView::DrawStatusIcons(const cChannel *Channel) {
+ if (!ViewElementImplemented(veStatusInfo)) {
+ return;
+ }
+
+ bool isRadio = !Channel->Vpid() && Channel->Apid(0);
+ bool hasVT = Channel->Vpid() && Channel->Tpid();
+ bool isStereo = Channel->Apid(0);
+ bool isDolby = Channel->Dpid(0);
+ bool isEncrypted = Channel->Ca();
+ bool isRecording = cRecordControls::Active();
+ cGlobalSortedTimers SortedTimers;// local and remote timers
+ for (int i = 0; i < SortedTimers.Size() && !isRecording; i++)
+ if (const cTimer *Timer = SortedTimers[i])
+ if (Timer->Recording())
+ isRecording = true;
+
+ map < string, int > intTokens;
+ intTokens.insert(pair<string,int>("isRadio", isRadio));
+ intTokens.insert(pair<string,int>("hasVT", hasVT));
+ intTokens.insert(pair<string,int>("isStereo", isStereo));
+ intTokens.insert(pair<string,int>("isDolby", isDolby));
+ intTokens.insert(pair<string,int>("isEncrypted", isEncrypted));
+ intTokens.insert(pair<string,int>("isRecording", isRecording));
+
+ DrawViewElement(veStatusInfo, NULL, &intTokens);
+}
+
+void cDisplayChannelView::ClearStatusIcons(void) {
+ ClearViewElement(veStatusInfo);
+}
+
+void cDisplayChannelView::DrawScreenResolution(void) {
+ if (!ViewElementImplemented(veScreenResolution)) {
+ return;
+ }
+
+ int screenWidth = 0;
+ int screenHeight = 0;
+ double aspect = 0;
+
+ cDevice::PrimaryDevice()->GetVideoSize(screenWidth, screenHeight, aspect);
+
+ if ((lastScreenWidth == screenWidth) && (lastScreenHeight == screenHeight))
+ return;
+
+ if ((screenWidth == 0) && (screenHeight == 0))
+ return;
+
+ lastScreenWidth = screenWidth;
+ lastScreenHeight = screenHeight;
+
+ bool isHD = false;
+ string resName = GetScreenResolutionString(screenWidth, screenHeight, &isHD);
+
+ bool isWideScreen = false;
+ string aspectName = GetScreenAspectString(aspect, &isWideScreen);
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ intTokens.insert(pair<string,int>("screenwidth", screenWidth));
+ intTokens.insert(pair<string,int>("screenheight", screenHeight));
+ intTokens.insert(pair<string,int>("isHD", isHD));
+ intTokens.insert(pair<string,int>("isWideScreen", isWideScreen));
+ stringTokens.insert(pair<string,string>("resolution", resName));
+ stringTokens.insert(pair<string,string>("aspect", aspectName));
+
+ ClearViewElement(veScreenResolution);
+ DrawViewElement(veScreenResolution, &stringTokens, &intTokens);
+}
+
+void cDisplayChannelView::ClearScreenResolution(void) {
+ ClearViewElement(veScreenResolution);
+ lastScreenWidth = 0;
+ lastScreenHeight = 0;
+}
+
+string cDisplayChannelView::GetScreenResolutionString(int width, int height, bool *isHD) {
+ string name = "";
+ switch (width) {
+ case 1920:
+ case 1440:
+ name = "hd1080i";
+ *isHD = true;
+ break;
+ case 1280:
+ if (height == 720)
+ name = "hd720p";
+ else
+ name = "hd1080i";
+ *isHD = true;
+ break;
+ case 720:
+ name = "sd576i";
+ break;
+ default:
+ name = "sd576i";
+ break;
+ }
+ return name;
+}
+
+string cDisplayChannelView::GetScreenAspectString(double aspect, bool *isWideScreen) {
+ string name = "";
+ *isWideScreen = false;
+ if (aspect == 4.0/3.0) {
+ name = "4:3";
+ *isWideScreen = false;
+ } else if (aspect == 16.0/9.0) {
+ name = "16:9";
+ *isWideScreen = true;
+ } else if (aspect == 2.21) {
+ name = "21:9";
+ *isWideScreen = true;
+ }
+ return name;
+}
+
+void cDisplayChannelView::DrawScraperContent(const cEvent *event) {
+ if (!event)
+ return;
+
+ if (!ViewElementImplemented(veScraperContent)) {
+ return;
+ }
+
+ static cPlugin *pScraper = GetScraperPlugin();
+ if (!pScraper) {
+ return;
+ }
+
+ ScraperGetPosterBanner call;
+ call.event = event;
+ if (pScraper->Service("GetPosterBanner", &call)) {
+ int mediaWidth = 0;
+ int mediaHeight = 0;
+ std::string mediaPath = "";
+ bool isBanner = false;
+
+ if ((call.type == tSeries) && call.banner.path.size() > 0) {
+ mediaWidth = call.banner.width;
+ mediaHeight = call.banner.height;
+ mediaPath = call.banner.path;
+ isBanner = true;
+ } else if (call.type == tMovie && call.poster.path.size() > 0 && call.poster.height > 0) {
+ mediaWidth = call.poster.width;
+ mediaHeight = call.poster.height;
+ mediaPath = call.poster.path;
+ } else
+ return;
+
+ map < string, int > intTokens;
+ map < string, string > stringTokens;
+ intTokens.insert(pair<string,int>("mediawidth", mediaWidth));
+ intTokens.insert(pair<string,int>("mediaheight", mediaHeight));
+ intTokens.insert(pair<string,int>("isbanner", isBanner));
+ stringTokens.insert(pair<string,string>("mediapath", mediaPath));
+ ClearViewElement(veScraperContent);
+ DrawViewElement(veScraperContent, &stringTokens, &intTokens);
+ }
+}
+
+void cDisplayChannelView::ClearScraperContent(void) {
+ ClearViewElement(veScraperContent);
+}
+
+void cDisplayChannelView::DrawSignal(void) {
+ if (!ViewElementImplemented(veSignalQuality)) {
+ return;
+ }
+ time_t Now = time(NULL);
+ if (Now != lastSignalDisplay) {
+ int SignalStrength = cDevice::ActualDevice()->SignalStrength();
+ int SignalQuality = cDevice::ActualDevice()->SignalQuality();
+ if (SignalStrength < 0) SignalStrength = 0;
+ if (SignalQuality < 0) SignalQuality = 0;
+ if ((SignalStrength == 0)&&(SignalQuality==0))
+ return;
+ if ((lastSignalStrength != SignalStrength) || (lastSignalQuality != SignalQuality)) {
+ map < string, int > intTokens;
+ map < string, string > stringTokens;
+ intTokens.insert(pair<string,int>("signalstrength", SignalStrength));
+ intTokens.insert(pair<string,int>("signalquality", SignalQuality));
+ ClearViewElement(veSignalQuality);
+ DrawViewElement(veSignalQuality, &stringTokens, &intTokens);
+ }
+ lastSignalStrength = SignalStrength;
+ lastSignalQuality = SignalQuality;
+ lastSignalDisplay = Now;
+ }
+}
+
+void cDisplayChannelView::DrawSignalBackground(void) {
+ if (!ViewElementImplemented(veSignalQualityBack)) {
+ return;
+ }
+ DrawViewElement(veSignalQualityBack);
+}
+
+
+void cDisplayChannelView::ClearSignal(void) {
+ ClearViewElement(veSignalQuality);
+}
+
+void cDisplayChannelView::ClearSignalBackground(void) {
+ ClearViewElement(veSignalQualityBack);
+}
+
+void cDisplayChannelView::DrawChannelGroups(const cChannel *Channel, cString ChannelName) {
+ if (!ViewElementImplemented(veChannelGroup)) {
+ return;
+ }
+
+ bool separatorExists = imgCache->SeparatorLogoExists(*ChannelName);
+ string separatorPath = separatorExists ? *ChannelName : "";
+
+ std::string prevChannelSep = GetChannelSep(Channel, true);
+ std::string nextChannelSep = GetChannelSep(Channel, false);
+ bool prevAvailable = (prevChannelSep.size() > 0)?true:false;
+ bool nextAvailable = (nextChannelSep.size() > 0)?true:false;
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ intTokens.insert(pair<string,int>("sepexists", separatorExists));
+ intTokens.insert(pair<string,int>("prevAvailable", prevAvailable));
+ intTokens.insert(pair<string,int>("nextAvailable", nextAvailable));
+ stringTokens.insert(pair<string,string>("group", *ChannelName));
+ stringTokens.insert(pair<string,string>("nextgroup", nextChannelSep));
+ stringTokens.insert(pair<string,string>("prevgroup", prevChannelSep));
+ stringTokens.insert(pair<string,string>("seppath", separatorPath));
+
+ ClearViewElement(veChannelGroup);
+ DrawViewElement(veChannelGroup, &stringTokens, &intTokens);
+}
+
+void cDisplayChannelView::ClearChannelGroups(void) {
+ ClearViewElement(veChannelGroup);
+}
+
+string cDisplayChannelView::GetChannelSep(const cChannel *channel, bool prev) {
+ std::string sepName = "";
+ const cChannel *sep = prev ? Channels.Prev(channel) :
+ Channels.Next(channel);
+ for (; sep; (prev)?(sep = Channels.Prev(sep)):(sep = Channels.Next(sep))) {
+ if (sep->GroupSep()) {
+ sepName = sep->Name();
+ break;
+ }
+ }
+ return sepName;
+}
+
+void cDisplayChannelView::DisplayMessage(eMessageType Type, const char *Text) {
+ if (!Text) {
+ ClearViewElement(veMessage);
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ stringTokens.insert(pair<string,string>("text", Text));
+
+ intTokens.insert(pair<string,int>("status", (Type == mtStatus) ? true : false));
+ intTokens.insert(pair<string,int>("info", (Type == mtInfo) ? true : false));
+ intTokens.insert(pair<string,int>("warning", (Type == mtWarning) ? true : false));
+ intTokens.insert(pair<string,int>("error", (Type == mtError) ? true : false));
+
+ ClearViewElement(veMessage);
+ DrawViewElement(veMessage, &stringTokens, &intTokens);
+}
+
+void cDisplayChannelView::Action(void) {
+ SetInitFinished();
+ FadeIn();
+ DoFlush();
+ cView::Action();
+}
diff --git a/views/displaychannelview.h b/views/displaychannelview.h
new file mode 100644
index 0000000..599ac5f
--- /dev/null
+++ b/views/displaychannelview.h
@@ -0,0 +1,49 @@
+#ifndef __DISPLAYCHANNELVIEW_H
+#define __DISPLAYCHANNELVIEW_H
+
+#include "../libtemplate/template.h"
+#include "view.h"
+
+class cDisplayChannelView : public cView {
+private:
+ cString lastDate;
+ int lastScreenWidth;
+ int lastScreenHeight;
+ int lastSignalDisplay;
+ int lastSignalStrength;
+ int lastSignalQuality;
+ string GetScreenResolutionString(int width, int height, bool *isHD);
+ string GetScreenAspectString(double aspect, bool *isWideScreen);
+ string GetChannelSep(const cChannel *channel, bool prev);
+ virtual void Action(void);
+public:
+ cDisplayChannelView(cTemplateView *tmplView);
+ virtual ~cDisplayChannelView();
+ bool createOsd(void);
+ void DrawBackground(void);
+ void DrawChannel(cString &number, cString &name, cString &id, bool switching);
+ void ClearChannel(void);
+ void DrawDate(void);
+ void DrawProgressBar(cString &start, cString &stop, int Current, int Total);
+ void ClearProgressBar(void);
+ void DrawProgressBarBack(void);
+ void ClearProgressBarBack(void);
+ void DrawEPGInfo(const cEvent *present, const cEvent *next, bool presentRecording, bool nextRecording);
+ void ClearEPGInfo(void);
+ void DrawStatusIcons(const cChannel *Channel);
+ void ClearStatusIcons(void);
+ void DrawScreenResolution(void);
+ void ClearScreenResolution(void);
+ void DrawScraperContent(const cEvent *event);
+ void ClearScraperContent(void);
+ void DrawSignal(void);
+ void DrawSignalBackground(void);
+ void ClearSignal(void);
+ void ClearSignalBackground(void);
+ void DrawChannelGroups(const cChannel *Channel, cString ChannelName);
+ void ClearChannelGroups(void);
+ void DisplayMessage(eMessageType Type, const char *Text);
+ void DoStart(void) { Start(); };
+ void Flush(void) { DoFlush(); };
+};
+#endif //__DISPLAYCHANNELVIEW_H
diff --git a/views/displaymenudetailview.c b/views/displaymenudetailview.c
new file mode 100644
index 0000000..acba9c6
--- /dev/null
+++ b/views/displaymenudetailview.c
@@ -0,0 +1,929 @@
+#include "displaymenudetailview.h"
+#include "../libcore/helpers.h"
+#include "../services/scraper2vdr.h"
+#include "../services/epgsearch.h"
+
+cDisplayMenuDetailView::cDisplayMenuDetailView(cTemplateView *tmplDetailView) : cView(tmplDetailView) {
+ event = NULL;
+ recording = NULL;
+ text = NULL;
+ detailViewInit = true;
+ currentTmplTab = NULL;
+ tabView = NULL;
+}
+
+cDisplayMenuDetailView::~cDisplayMenuDetailView() {
+ CancelSave();
+ if (tabView)
+ delete tabView;
+}
+
+void cDisplayMenuDetailView::Clear(void) {
+ ClearViewElement(veDetailHeader);
+ ClearViewElement(veScrollbar);
+ ClearViewElement(veTabLabels);
+}
+
+void cDisplayMenuDetailView::Render(void) {
+ if (detailViewInit) {
+ DrawHeader();
+ DoFlush();
+ SetTokens();
+ InitTabs();
+ currentTmplTab = *atIt;
+ detailViewInit = false;
+ }
+ if (!tabView) {
+ tabView = new cDisplayMenuTabView(currentTmplTab);
+ tabView->SetTokens(&intTokens, &stringTokens, &loopTokens);
+ tabView->CreateTab();
+ tabView->Start();
+ }
+ DrawScrollbar();
+ DrawTabLabels();
+}
+
+void cDisplayMenuDetailView::KeyLeft(void) {
+ if (activeTabs.size() > 1) {
+ currentTmplTab = GetPrevTab();
+ delete tabView;
+ tabView = NULL;
+ Render();
+ DoFlush();
+ } else {
+ bool scrolled = tabView->KeyLeft();
+ if (scrolled) {
+ DrawScrollbar();
+ DoFlush();
+ }
+ }
+}
+
+void cDisplayMenuDetailView::KeyRight(void) {
+ if (activeTabs.size() > 1) {
+ currentTmplTab = GetNextTab();
+ delete tabView;
+ tabView = NULL;
+ Render();
+ DoFlush();
+ } else {
+ bool scrolled = tabView->KeyRight();
+ if (scrolled) {
+ DrawScrollbar();
+ DoFlush();
+ }
+ }
+}
+
+void cDisplayMenuDetailView::KeyUp(void) {
+ if (!tabView)
+ return;
+ bool scrolled = tabView->KeyUp();
+ if (scrolled) {
+ DrawScrollbar();
+ DoFlush();
+ }
+}
+
+void cDisplayMenuDetailView::KeyDown(void) {
+ if (!tabView)
+ return;
+ bool scrolled = tabView->KeyDown();
+ if (scrolled) {
+ DrawScrollbar();
+ DoFlush();
+ }
+}
+
+
+void cDisplayMenuDetailView::SetTokens(void) {
+ if (event) {
+ stringTokens.insert(pair<string,string>("title", event->Title() ? event->Title() : ""));
+ stringTokens.insert(pair<string,string>("shorttext", event->ShortText() ? event->ShortText() : ""));
+ stringTokens.insert(pair<string,string>("description", event->Description() ? event->Description() : ""));
+ stringTokens.insert(pair<string,string>("start", *(event->GetTimeString())));
+ stringTokens.insert(pair<string,string>("stop", *(event->GetEndTimeString())));
+ stringTokens.insert(pair<string,string>("day", *WeekDayName(event->StartTime())));
+ stringTokens.insert(pair<string,string>("date", *ShortDateString(event->StartTime())));
+ stringTokens.insert(pair<string,string>("channelid", *(event->ChannelID().ToString())));
+
+ bool isRunning = false;
+ time_t now = time(NULL);
+ if ((now >= event->StartTime()) && (now <= event->EndTime()))
+ isRunning = true;
+ intTokens.insert(pair<string,int>("running", isRunning));
+ if (isRunning) {
+ intTokens.insert(pair<string,int>("elapsed", (now - event->StartTime())/60));
+ } else {
+ intTokens.insert(pair<string,int>("elapsed", 0));
+ }
+ intTokens.insert(pair<string,int>("duration", event->Duration() / 60));
+
+ vector< map< string, string > > reruns;
+ bool hasReruns = LoadReruns(&reruns);
+ loopTokens.insert(pair<string, vector< map< string, string > > >("reruns", reruns));
+
+ intTokens.insert(pair<string,int>("hasreruns", hasReruns));
+
+ SetScraperTokens();
+ SetEpgPictures(event->EventID());
+
+ } else if (recording) {
+ string name = recording->Name() ? recording->Name() : "";
+ stringTokens.insert(pair<string,string>("name", name));
+
+ const cRecordingInfo *info = recording->Info();
+ if (info) {
+ stringTokens.insert(pair<string,string>("shorttext", info->ShortText() ? info->ShortText() : ""));
+ stringTokens.insert(pair<string,string>("description", info->Description() ? info->Description() : ""));
+ const cEvent *event = info->GetEvent();
+ if (event) {
+ string recDate = *(event->GetDateString());
+ string recTime = *(event->GetTimeString());
+ if (recDate.find("1970") != string::npos) {
+ time_t start = recording->Start();
+ recDate = *DateString(start);
+ recTime = *TimeString(start);
+ }
+ int duration = event->Duration() / 60;
+ int recDuration = recording->LengthInSeconds();
+ recDuration = (recDuration>0)?(recDuration / 60):0;
+ stringTokens.insert(pair<string,string>("date", recDate.c_str()));
+ stringTokens.insert(pair<string,string>("time", recTime.c_str()));
+ intTokens.insert(pair<string,int>("duration", recDuration));
+ intTokens.insert(pair<string,int>("durationevent", duration));
+ }
+ } else {
+ stringTokens.insert(pair<string,string>("shorttext", ""));
+ stringTokens.insert(pair<string,string>("description", ""));
+ int recDuration = recording->LengthInSeconds();
+ recDuration = (recDuration>0)?(recDuration / 60):0;
+ stringTokens.insert(pair<string,string>("date", ""));
+ stringTokens.insert(pair<string,string>("time", ""));
+ intTokens.insert(pair<string,int>("duration", recDuration));
+ intTokens.insert(pair<string,int>("durationevent", 0));
+ }
+ LoadRecordingInformation();
+ SetScraperTokens();
+ SetRecordingImages(recording->FileName());
+ } else if (text) {
+ stringTokens.insert(pair<string,string>("text", text));
+ } else {
+ intTokens.insert(pair<string,int>("running", false));
+ intTokens.insert(pair<string,int>("hasreruns", false));
+ }
+}
+
+void cDisplayMenuDetailView::SetScraperTokens(void) {
+ static cPlugin *pScraper = GetScraperPlugin();
+ if (!pScraper || (!event && !recording)) {
+ intTokens.insert(pair<string,int>("ismovie", false));
+ intTokens.insert(pair<string,int>("isseries", false));
+ return;
+ }
+
+ ScraperGetEventType getType;
+ getType.event = event;
+ getType.recording = recording;
+ if (!pScraper->Service("GetEventType", &getType)) {
+ intTokens.insert(pair<string,int>("ismovie", false));
+ intTokens.insert(pair<string,int>("isseries", false));
+ return;
+ }
+
+ if (getType.type == tMovie) {
+ cMovie movie;
+ movie.movieId = getType.movieId;
+ pScraper->Service("GetMovie", &movie);
+ intTokens.insert(pair<string,int>("ismovie", true));
+ intTokens.insert(pair<string,int>("isseries", false));
+
+ stringTokens.insert(pair<string,string>("movietitle", movie.title));
+ stringTokens.insert(pair<string,string>("movieoriginalTitle", movie.originalTitle));
+ stringTokens.insert(pair<string,string>("movietagline", movie.tagline));
+ stringTokens.insert(pair<string,string>("movieoverview", movie.overview));
+ stringTokens.insert(pair<string,string>("moviegenres", movie.genres));
+ stringTokens.insert(pair<string,string>("moviehomepage", movie.homepage));
+ stringTokens.insert(pair<string,string>("moviereleasedate", movie.releaseDate));
+ stringstream pop;
+ pop << movie.popularity;
+ stringTokens.insert(pair<string,string>("moviepopularity", pop.str()));
+ stringstream vote;
+ vote << movie.voteAverage;
+ stringTokens.insert(pair<string,string>("movievoteaverage", pop.str()));
+ stringTokens.insert(pair<string,string>("posterpath", movie.poster.path));
+ stringTokens.insert(pair<string,string>("fanartpath", movie.fanart.path));
+ stringTokens.insert(pair<string,string>("collectionposterpath", movie.collectionPoster.path));
+ stringTokens.insert(pair<string,string>("collectionfanartpath", movie.collectionFanart.path));
+
+ intTokens.insert(pair<string,int>("movieadult", movie.adult));
+ intTokens.insert(pair<string,int>("moviebudget", movie.budget));
+ intTokens.insert(pair<string,int>("movierevenue", movie.revenue));
+ intTokens.insert(pair<string,int>("movieruntime", movie.runtime));
+ intTokens.insert(pair<string,int>("posterwidth", movie.poster.width));
+ intTokens.insert(pair<string,int>("posterheight", movie.poster.height));
+ intTokens.insert(pair<string,int>("fanartwidth", movie.fanart.width));
+ intTokens.insert(pair<string,int>("fanartheight", movie.fanart.height));
+ intTokens.insert(pair<string,int>("collectionposterwidth", movie.collectionPoster.width));
+ intTokens.insert(pair<string,int>("collectionposterheight", movie.collectionPoster.height));
+ intTokens.insert(pair<string,int>("collectionfanartwidth", movie.collectionFanart.width));
+ intTokens.insert(pair<string,int>("collectionfanartheight", movie.collectionFanart.height));
+
+ vector< map< string, string > > actors;
+ for (vector<cActor>::iterator act = movie.actors.begin(); act != movie.actors.end(); act++) {
+ map< string, string > actor;
+ actor.insert(pair<string, string>("actors[name]", (*act).name));
+ actor.insert(pair<string, string>("actors[role]", (*act).role));
+ actor.insert(pair<string, string>("actors[thumb]", (*act).actorThumb.path));
+ stringstream actWidth, actHeight;
+ actWidth << (*act).actorThumb.width;
+ actHeight << (*act).actorThumb.height;
+ actor.insert(pair<string, string>("actors[thumbwidth]", actWidth.str()));
+ actor.insert(pair<string, string>("actors[thumbheight]", actHeight.str()));
+ actors.push_back(actor);
+ }
+ loopTokens.insert(pair<string, vector< map< string, string > > >("actors", actors));
+
+ } else if (getType.type == tSeries) {
+ cSeries series;
+ series.seriesId = getType.seriesId;
+ series.episodeId = getType.episodeId;
+ pScraper->Service("GetSeries", &series);
+ intTokens.insert(pair<string,int>("ismovie", false));
+ intTokens.insert(pair<string,int>("isseries", true));
+ //Series Basics
+ stringTokens.insert(pair<string,string>("seriesname", series.name));
+ stringTokens.insert(pair<string,string>("seriesoverview", series.overview));
+ stringTokens.insert(pair<string,string>("seriesfirstaired", series.firstAired));
+ stringTokens.insert(pair<string,string>("seriesnetwork", series.network));
+ stringTokens.insert(pair<string,string>("seriesgenre", series.genre));
+ stringstream rating;
+ rating << series.rating;
+ stringTokens.insert(pair<string,string>("seriesrating", rating.str()));
+ stringTokens.insert(pair<string,string>("seriesstatus", series.status));
+ //Episode Information
+ intTokens.insert(pair<string,int>("episodenumber", series.episode.number));
+ intTokens.insert(pair<string,int>("episodeseason", series.episode.season));
+ stringTokens.insert(pair<string,string>("episodetitle", series.episode.name));
+ stringTokens.insert(pair<string,string>("episodefirstaired", series.episode.firstAired));
+ stringTokens.insert(pair<string,string>("episodegueststars", series.episode.guestStars));
+ stringTokens.insert(pair<string,string>("episodeoverview", series.episode.overview));
+ stringstream eprating;
+ eprating << series.episode.rating;
+ stringTokens.insert(pair<string,string>("episoderating", eprating.str()));
+ intTokens.insert(pair<string,int>("episodeimagewidth", series.episode.episodeImage.width));
+ intTokens.insert(pair<string,int>("episodeimageheight", series.episode.episodeImage.height));
+ stringTokens.insert(pair<string,string>("episodeimagepath", series.episode.episodeImage.path));
+ //Seasonposter
+ intTokens.insert(pair<string,int>("seasonposterwidth", series.seasonPoster.width));
+ intTokens.insert(pair<string,int>("seasonposterheight", series.seasonPoster.height));
+ stringTokens.insert(pair<string,string>("seasonposterpath", series.seasonPoster.path));
+
+ //Posters
+ int current = 1;
+ for(vector<cTvMedia>::iterator poster = series.posters.begin(); poster != series.posters.end(); poster++) {
+ stringstream labelWidth, labelHeight, labelPath;
+ labelWidth << "seriesposter" << current << "width";
+ labelHeight << "seriesposter" << current << "height";
+ labelPath << "seriesposter" << current << "path";
+
+ intTokens.insert(pair<string,int>(labelWidth.str(), (*poster).width));
+ intTokens.insert(pair<string,int>(labelHeight.str(), (*poster).height));
+ stringTokens.insert(pair<string,string>(labelPath.str(), (*poster).path));
+ current++;
+ }
+ if (current < 3) {
+ for (; current < 4; current++) {
+ stringstream labelWidth, labelHeight, labelPath;
+ labelWidth << "seriesposter" << current << "width";
+ labelHeight << "seriesposter" << current << "height";
+ labelPath << "seriesposter" << current << "path";
+
+ intTokens.insert(pair<string,int>(labelWidth.str(), 0));
+ intTokens.insert(pair<string,int>(labelHeight.str(), 0));
+ stringTokens.insert(pair<string,string>(labelPath.str(), ""));
+ }
+ }
+
+ //Banners
+ current = 1;
+ for(vector<cTvMedia>::iterator banner = series.banners.begin(); banner != series.banners.end(); banner++) {
+ stringstream labelWidth, labelHeight, labelPath;
+ labelWidth << "seriesbanner" << current << "width";
+ labelHeight << "seriesbanner" << current << "height";
+ labelPath << "seriesbanner" << current << "path";
+
+ intTokens.insert(pair<string,int>(labelWidth.str(), (*banner).width));
+ intTokens.insert(pair<string,int>(labelHeight.str(), (*banner).height));
+ stringTokens.insert(pair<string,string>(labelPath.str(), (*banner).path));
+ current++;
+ }
+ if (current < 3) {
+ for (; current < 4; current++) {
+ stringstream labelWidth, labelHeight, labelPath;
+ labelWidth << "seriesbanner" << current << "width";
+ labelHeight << "seriesbanner" << current << "height";
+ labelPath << "seriesbanner" << current << "path";
+
+ intTokens.insert(pair<string,int>(labelWidth.str(), 0));
+ intTokens.insert(pair<string,int>(labelHeight.str(), 0));
+ stringTokens.insert(pair<string,string>(labelPath.str(), ""));
+ }
+ }
+
+ //Fanarts
+ current = 1;
+ for(vector<cTvMedia>::iterator fanart = series.fanarts.begin(); fanart != series.fanarts.end(); fanart++) {
+ stringstream labelWidth, labelHeight, labelPath;
+ labelWidth << "seriesfanart" << current << "width";
+ labelHeight << "seriesfanart" << current << "height";
+ labelPath << "seriesfanart" << current << "path";
+
+ intTokens.insert(pair<string,int>(labelWidth.str(), (*fanart).width));
+ intTokens.insert(pair<string,int>(labelHeight.str(), (*fanart).height));
+ stringTokens.insert(pair<string,string>(labelPath.str(), (*fanart).path));
+ current++;
+ }
+ if (current < 3) {
+ for (; current < 4; current++) {
+ stringstream labelWidth, labelHeight, labelPath;
+ labelWidth << "seriesfanart" << current << "width";
+ labelHeight << "seriesfanart" << current << "height";
+ labelPath << "seriesfanart" << current << "path";
+
+ intTokens.insert(pair<string,int>(labelWidth.str(), 0));
+ intTokens.insert(pair<string,int>(labelHeight.str(), 0));
+ stringTokens.insert(pair<string,string>(labelPath.str(), ""));
+ }
+ }
+
+ //Actors
+ vector< map< string, string > > actors;
+ for (vector<cActor>::iterator act = series.actors.begin(); act != series.actors.end(); act++) {
+ map< string, string > actor;
+ actor.insert(pair<string, string>("actors[name]", (*act).name));
+ actor.insert(pair<string, string>("actors[role]", (*act).role));
+ actor.insert(pair<string, string>("actors[thumb]", (*act).actorThumb.path));
+ stringstream actWidth, actHeight;
+ actWidth << (*act).actorThumb.width;
+ actHeight << (*act).actorThumb.height;
+ actor.insert(pair<string, string>("actors[thumbwidth]", actWidth.str()));
+ actor.insert(pair<string, string>("actors[thumbheight]", actHeight.str()));
+ actors.push_back(actor);
+ }
+ loopTokens.insert(pair<string, vector< map< string, string > > >("actors", actors));
+
+ } else {
+ intTokens.insert(pair<string,int>("ismovie", false));
+ intTokens.insert(pair<string,int>("isseries", false));
+ }
+
+}
+
+void cDisplayMenuDetailView::InitTabs(void) {
+ tmplView->InitViewTabIterator();
+ cTemplateViewTab *tmplTab = NULL;
+ while(tmplTab = tmplView->GetNextViewTab()) {
+ tmplTab->ParseDynamicParameters(&intTokens, true);
+ tmplTab->ClearDynamicFunctionParameters();
+ tmplTab->ParseDynamicFunctionParameters(&stringTokens, &intTokens);
+ if (tmplTab->DoExecute()) {
+ activeTabs.push_back(tmplTab);
+ }
+ }
+ atIt = activeTabs.begin();
+}
+
+bool cDisplayMenuDetailView::LoadReruns(vector< map< string, string > > *reruns) {
+ if (!event)
+ return false;
+
+ cPlugin *epgSearchPlugin = cPluginManager::GetPlugin("epgsearch");
+ if (!epgSearchPlugin)
+ return false;
+
+ if (isempty(event->Title()))
+ return false;
+
+ int maxNumReruns = 10;
+
+ Epgsearch_searchresults_v1_0 data;
+ string strQuery = event->Title();
+ data.useSubTitle = true;
+ data.query = (char *)strQuery.c_str();
+ data.mode = 0;
+ data.channelNr = 0;
+ data.useTitle = true;
+ data.useDescription = false;
+
+ bool foundRerun = false;
+ if (epgSearchPlugin->Service("Epgsearch-searchresults-v1.0", &data)) {
+ cList<Epgsearch_searchresults_v1_0::cServiceSearchResult>* list = data.pResultList;
+ if (list && (list->Count() > 1)) {
+ foundRerun = true;
+ int i = 0;
+ for (Epgsearch_searchresults_v1_0::cServiceSearchResult *r = list->First(); r && i < maxNumReruns; r = list->Next(r)) {
+ if ((event->ChannelID() == r->event->ChannelID()) && (event->StartTime() == r->event->StartTime()))
+ continue;
+ i++;
+ map< string, string > rerun;
+ rerun.insert(pair<string, string>("reruns[title]", r->event->Title() ? r->event->Title() : ""));
+ rerun.insert(pair<string, string>("reruns[shorttext]", r->event->ShortText() ? r->event->ShortText() : ""));
+ rerun.insert(pair<string, string>("reruns[start]", *(r->event->GetTimeString())));
+ rerun.insert(pair<string, string>("reruns[start]", *(r->event->GetTimeString())));
+ rerun.insert(pair<string, string>("reruns[stop]", *(r->event->GetEndTimeString())));
+ rerun.insert(pair<string, string>("reruns[date]", *ShortDateString(r->event->StartTime())));
+ rerun.insert(pair<string, string>("reruns[day]", *WeekDayName(r->event->StartTime())));
+ string channelID = *(r->event->ChannelID().ToString());
+ rerun.insert(pair<string, string>("reruns[channelid]", channelID));
+ bool logoExists = imgCache->LogoExists(channelID);
+ rerun.insert(pair<string, string>("reruns[channellogoexists]", logoExists ? "1" : "0"));
+
+ cChannel *channel = Channels.GetByChannelID(r->event->ChannelID(), true, true);
+ if (channel) {
+ stringstream channelNumber;
+ channelNumber << channel->Number();
+ rerun.insert(pair<string, string>("reruns[channelname]", channel->ShortName(true)));
+ rerun.insert(pair<string, string>("reruns[channelnumber]", channelNumber.str()));
+ } else {
+ rerun.insert(pair<string, string>("reruns[channelname]", ""));
+ rerun.insert(pair<string, string>("reruns[channelnumber]", ""));
+ }
+ reruns->push_back(rerun);
+ }
+ delete list;
+ }
+ }
+ return foundRerun;
+}
+
+void cDisplayMenuDetailView::LoadRecordingInformation(void) {
+ const cRecordingInfo *Info = recording->Info();
+ if (!Info)
+ return;
+ unsigned long long nRecSize = -1;
+ unsigned long long nFileSize[1000];
+ nFileSize[0] = 0;
+ int i = 0;
+ struct stat filebuf;
+ cString filename;
+ int rc = 0;
+ do {
+ if (recording->IsPesRecording())
+ filename = cString::sprintf("%s/%03d.vdr", recording->FileName(), ++i);
+ else
+ filename = cString::sprintf("%s/%05d.ts", recording->FileName(), ++i);
+ rc = stat(filename, &filebuf);
+ if (rc == 0)
+ nFileSize[i] = nFileSize[i-1] + filebuf.st_size;
+ else
+ if (ENOENT != errno) {
+ nRecSize = -1;
+ }
+ } while (i <= 999 && !rc);
+ nRecSize = nFileSize[i-1];
+
+ cMarks marks;
+ bool fHasMarks = marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording()) && marks.Count();
+ cIndexFile *index = new cIndexFile(recording->FileName(), false, recording->IsPesRecording());
+
+ int nCutLength = 0;
+ long nCutInFrame = 0;
+ unsigned long long nRecSizeCut = nRecSize < 0 ? -1 : 0;
+ unsigned long long nCutInOffset = 0;
+
+ if (fHasMarks && index) {
+ uint16_t FileNumber;
+ off_t FileOffset;
+
+ bool fCutIn = true;
+ cMark *mark = marks.First();
+ while (mark) {
+ int pos = mark->Position();
+ index->Get(pos, &FileNumber, &FileOffset); //TODO: will disc spin up?
+ if (fCutIn) {
+ nCutInFrame = pos;
+ fCutIn = false;
+ if (nRecSize >= 0)
+ nCutInOffset = nFileSize[FileNumber-1] + FileOffset;
+ } else {
+ nCutLength += pos - nCutInFrame;
+ fCutIn = true;
+ if (nRecSize >= 0)
+ nRecSizeCut += nFileSize[FileNumber-1] + FileOffset - nCutInOffset;
+ }
+ cMark *nextmark = marks.Next(mark);
+ mark = nextmark;
+ }
+ if (!fCutIn) {
+ nCutLength += index->Last() - nCutInFrame;
+ index->Get(index->Last() - 1, &FileNumber, &FileOffset);
+ if (nRecSize >= 0)
+ nRecSizeCut += nFileSize[FileNumber-1] + FileOffset - nCutInOffset;
+ }
+ }
+
+ if (nRecSize < 0) {
+ if ((nRecSize = ReadSizeVdr(recording->FileName())) < 0) {
+ nRecSize = DirSizeMB(recording->FileName());
+ }
+ }
+ if (nRecSize >= 0) {
+ cString strRecSize = "";
+ cString strRecSizeCut = "";
+
+ if (fHasMarks) {
+ if (nRecSize > MEGABYTE(1023)) {
+ strRecSize = cString::sprintf("%.2f GB", (float)nRecSize / MEGABYTE(1024));
+ strRecSizeCut = cString::sprintf("%.2f GB", (float)nRecSizeCut / MEGABYTE(1024));
+ } else {
+ strRecSize = cString::sprintf("%lld MB", nRecSize / MEGABYTE(1));
+ strRecSizeCut = cString::sprintf("%lld MB", nRecSizeCut / MEGABYTE(1));
+ }
+ } else {
+ if (nRecSize > MEGABYTE(1023)) {
+ strRecSize = cString::sprintf("%.2f GB", (float)nRecSize / MEGABYTE(1024));
+ strRecSizeCut = strRecSize;
+ } else {
+ strRecSize = cString::sprintf("%lld MB", nRecSize / MEGABYTE(1));
+ strRecSizeCut = strRecSize;
+ }
+ }
+ stringTokens.insert(pair<string,string>("recordingsize", *strRecSize));
+ stringTokens.insert(pair<string,string>("recordingsizecutted", *strRecSizeCut));
+ } else {
+ stringTokens.insert(pair<string,string>("recordingsize", ""));
+ stringTokens.insert(pair<string,string>("recordingsizecutted", ""));
+ }
+
+ cChannel *channel = Channels.GetByChannelID(Info->ChannelID());
+ if (channel) {
+ stringTokens.insert(pair<string,string>("recchannelname", channel->Name()));
+ intTokens.insert(pair<string,int>("recchannelnumber", channel->Number()));
+ }
+
+ if (index) {
+ int nLastIndex = index->Last();
+ if (nLastIndex) {
+ string strLength = *IndexToHMSF(nLastIndex, false, recording->FramesPerSecond());
+ string strLengthCutted = "";
+ if (fHasMarks) {
+ strLengthCutted = *IndexToHMSF(nCutLength, false, recording->FramesPerSecond());
+ } else {
+ strLengthCutted = strLength;
+ }
+ string strBitrate = *cString::sprintf("%.2f MBit/s", (float)nRecSize / nLastIndex * recording->FramesPerSecond() * 8 / MEGABYTE(1));
+ stringTokens.insert(pair<string,string>("recordinglength", strLength));
+ stringTokens.insert(pair<string,string>("recordinglengthcutted", strLengthCutted));
+ stringTokens.insert(pair<string,string>("recordingbitrate", strBitrate));
+ }
+ delete index;
+ }
+
+ string recFormat = recording->IsPesRecording() ? "PES" : "TS";
+ stringTokens.insert(pair<string,string>("recordingformat", recFormat));
+
+ bool searchTimerFound = false;
+ if (Info) {
+ const char *aux = NULL;
+ aux = Info->Aux();
+ if (aux) {
+ string strAux = aux;
+ string auxEpgsearch = StripXmlTag(strAux, "epgsearch");
+ if (!auxEpgsearch.empty()) {
+ string searchTimer = StripXmlTag(auxEpgsearch, "searchtimer");
+ if (!searchTimer.empty()) {
+ stringTokens.insert(pair<string,string>("searchtimer", searchTimer));
+ searchTimerFound = true;
+ }
+ }
+ }
+ }
+ if (!searchTimerFound)
+ stringTokens.insert(pair<string,string>("searchtimer", "n.a."));
+}
+
+string cDisplayMenuDetailView::StripXmlTag(string &Line, const char *Tag) {
+ // set the search strings
+ stringstream strStart, strStop;
+ strStart << "<" << Tag << ">";
+ strStop << "</" << Tag << ">";
+ // find the strings
+ string::size_type locStart = Line.find(strStart.str());
+ string::size_type locStop = Line.find(strStop.str());
+ if (locStart == string::npos || locStop == string::npos)
+ return "";
+ // extract relevant text
+ int pos = locStart + strStart.str().size();
+ int len = locStop - pos;
+ return len < 0 ? "" : Line.substr(pos, len);
+}
+
+
+int cDisplayMenuDetailView::ReadSizeVdr(const char *strPath) {
+ int dirSize = -1;
+ char buffer[20];
+ char *strFilename = NULL;
+ if (-1 != asprintf(&strFilename, "%s/size.vdr", strPath)) {
+ struct stat st;
+ if (stat(strFilename, &st) == 0) {
+ int fd = open(strFilename, O_RDONLY);
+ if (fd >= 0) {
+ if (safe_read(fd, &buffer, sizeof(buffer)) >= 0) {
+ dirSize = atoi(buffer);
+ }
+ close(fd);
+ }
+ }
+ free(strFilename);
+ }
+ return dirSize;
+}
+
+void cDisplayMenuDetailView::SetEpgPictures(int eventId) {
+ for (int i=0; i<3; i++) {
+ stringstream picName;
+ picName << eventId << "_" << i;
+ bool epgPicAvailable = FileExists(*config.epgImagePath, picName.str(), "jpg");
+ stringstream available;
+ stringstream path;
+ available << "epgpic" << i+1 << "avaialble";
+ path << "epgpic" << i+1 << "path";
+ if (epgPicAvailable) {
+ intTokens.insert(pair<string,int>(available.str(), true));
+ stringTokens.insert(pair<string,string>(path.str(), *cString::sprintf("%s%s.jpg", *config.epgImagePath, picName.str().c_str())));
+ } else {
+ intTokens.insert(pair<string,int>(available.str(), false));
+ stringTokens.insert(pair<string,string>(path.str(), ""));
+ }
+ }
+}
+
+void cDisplayMenuDetailView::SetRecordingImages(const char *recPath) {
+ if (!recPath) {
+ intTokens.insert(pair<string,int>("recimg1avaialble", false));
+ intTokens.insert(pair<string,int>("recimg2avaialble", false));
+ intTokens.insert(pair<string,int>("recimg3avaialble", false));
+ stringTokens.insert(pair<string,string>("recimg1path", ""));
+ stringTokens.insert(pair<string,string>("recimg2path", ""));
+ stringTokens.insert(pair<string,string>("recimg3path", ""));
+ return;
+ }
+
+ string path = recPath;
+ DIR *dirHandle;
+ struct dirent *dirEntry;
+ dirHandle = opendir(recPath);
+ if (!dirHandle) {
+ intTokens.insert(pair<string,int>("recimg1avaialble", false));
+ intTokens.insert(pair<string,int>("recimg2avaialble", false));
+ intTokens.insert(pair<string,int>("recimg3avaialble", false));
+ stringTokens.insert(pair<string,string>("recimg1path", ""));
+ stringTokens.insert(pair<string,string>("recimg2path", ""));
+ stringTokens.insert(pair<string,string>("recimg3path", ""));
+ return;
+ }
+
+ int picsFound = 0;
+ while ( 0 != (dirEntry = readdir(dirHandle))) {
+ if (endswith(dirEntry->d_name, "jpg")) {
+ string fileName = dirEntry->d_name;
+ stringstream available;
+ available << "recimg" << picsFound+1 << "avaialble";
+ stringstream path;
+ path << "recimg" << picsFound+1 << "path";
+ intTokens.insert(pair<string,int>(available.str(), true));
+ stringTokens.insert(pair<string,string>(path.str(), *cString::sprintf("%s/%s", recPath, fileName.c_str())));
+ picsFound++;
+ }
+ if (picsFound == 3) {
+ break;
+ }
+ }
+ for (int i=picsFound; i<3; i++) {
+ stringstream available;
+ available << "recimg" << i+1 << "avaialble";
+ stringstream path;
+ path << "recimg" << i+1 << "path";
+ intTokens.insert(pair<string,int>(available.str(), false));
+ stringTokens.insert(pair<string,string>(path.str(), ""));
+ }
+ closedir(dirHandle);
+}
+
+void cDisplayMenuDetailView::DrawHeader(void) {
+ map < string, string > headerStringTokens;
+ map < string, int > headerIntTokens;
+
+ if (event || recording) {
+ static cPlugin *pScraper = GetScraperPlugin();
+ if (!pScraper) {
+ headerIntTokens.insert(pair<string,int>("ismovie", false));
+ headerIntTokens.insert(pair<string,int>("isseries", false));
+ headerIntTokens.insert(pair<string,int>("posteravailable", false));
+ headerIntTokens.insert(pair<string,int>("banneravailable", false));
+ } else {
+ ScraperGetEventType getType;
+ getType.event = event;
+ getType.recording = recording;
+ if (!pScraper->Service("GetEventType", &getType)) {
+ headerIntTokens.insert(pair<string,int>("ismovie", false));
+ headerIntTokens.insert(pair<string,int>("isseries", false));
+ headerIntTokens.insert(pair<string,int>("posteravailable", false));
+ headerIntTokens.insert(pair<string,int>("banneravailable", false));
+ } else {
+ if (getType.type == tMovie) {
+ cMovie movie;
+ movie.movieId = getType.movieId;
+ pScraper->Service("GetMovie", &movie);
+ headerIntTokens.insert(pair<string,int>("ismovie", true));
+ headerIntTokens.insert(pair<string,int>("isseries", false));
+ headerIntTokens.insert(pair<string,int>("posteravailable", true));
+ headerIntTokens.insert(pair<string,int>("banneravailable", false));
+ headerStringTokens.insert(pair<string,string>("posterpath", movie.poster.path));
+ headerIntTokens.insert(pair<string,int>("posterwidth", movie.poster.width));
+ headerIntTokens.insert(pair<string,int>("posterheight", movie.poster.height));
+ } else if (getType.type == tSeries) {
+ cSeries series;
+ series.seriesId = getType.seriesId;
+ series.episodeId = getType.episodeId;
+ pScraper->Service("GetSeries", &series);
+ headerIntTokens.insert(pair<string,int>("ismovie", false));
+ headerIntTokens.insert(pair<string,int>("isseries", true));
+ vector<cTvMedia>::iterator poster = series.posters.begin();
+ if (poster != series.posters.end()) {
+ headerIntTokens.insert(pair<string,int>("posterwidth", (*poster).width));
+ headerIntTokens.insert(pair<string,int>("posterheight", (*poster).height));
+ headerStringTokens.insert(pair<string,string>("posterpath", (*poster).path));
+ headerIntTokens.insert(pair<string,int>("posteravailable", true));
+ } else {
+ headerIntTokens.insert(pair<string,int>("posterwidth", 0));
+ headerIntTokens.insert(pair<string,int>("posterheight", 0));
+ headerStringTokens.insert(pair<string,string>("posterpath", ""));
+ headerIntTokens.insert(pair<string,int>("posteravailable", false));
+ }
+ vector<cTvMedia>::iterator banner = series.banners.begin();
+ if (banner != series.banners.end()) {
+ headerIntTokens.insert(pair<string,int>("bannerwidth", (*banner).width));
+ headerIntTokens.insert(pair<string,int>("bannerheight", (*banner).height));
+ headerStringTokens.insert(pair<string,string>("bannerpath", (*banner).path));
+ headerIntTokens.insert(pair<string,int>("banneravailable", true));
+ } else {
+ headerIntTokens.insert(pair<string,int>("bannerwidth", 0));
+ headerIntTokens.insert(pair<string,int>("bannerheight", 0));
+ headerStringTokens.insert(pair<string,string>("bannerpath", ""));
+ headerIntTokens.insert(pair<string,int>("banneravailable", false));
+ }
+ } else {
+ headerIntTokens.insert(pair<string,int>("ismovie", false));
+ headerIntTokens.insert(pair<string,int>("isseries", false));
+ headerIntTokens.insert(pair<string,int>("posteravailable", false));
+ headerIntTokens.insert(pair<string,int>("banneravailable", false));
+ }
+ }
+ }
+ }
+
+ if (event) {
+ headerStringTokens.insert(pair<string,string>("title", event->Title() ? event->Title() : ""));
+ headerStringTokens.insert(pair<string,string>("shorttext", event->ShortText() ? event->ShortText() : ""));
+ headerStringTokens.insert(pair<string,string>("start", *(event->GetTimeString())));
+ headerStringTokens.insert(pair<string,string>("stop", *(event->GetEndTimeString())));
+ headerStringTokens.insert(pair<string,string>("day", *WeekDayName(event->StartTime())));
+ headerStringTokens.insert(pair<string,string>("date", *ShortDateString(event->StartTime())));
+ headerStringTokens.insert(pair<string,string>("channelid", *(event->ChannelID().ToString())));
+
+ bool isRunning = false;
+ time_t now = time(NULL);
+ if ((now >= event->StartTime()) && (now <= event->EndTime()))
+ isRunning = true;
+ headerIntTokens.insert(pair<string,int>("running", isRunning));
+ if (isRunning) {
+ headerIntTokens.insert(pair<string,int>("elapsed", (now - event->StartTime())/60));
+ } else {
+ headerIntTokens.insert(pair<string,int>("elapsed", 0));
+ }
+ headerIntTokens.insert(pair<string,int>("duration", event->Duration() / 60));
+
+ stringstream epgImageName;
+ epgImageName << event->EventID();
+ bool epgPicAvailable = FileExists(*config.epgImagePath, epgImageName.str(), "jpg");
+ if (epgPicAvailable) {
+ headerIntTokens.insert(pair<string,int>("epgpicavailable", true));
+ headerStringTokens.insert(pair<string,string>("epgpicpath", *cString::sprintf("%s%s.jpg", *config.epgImagePath, epgImageName.str().c_str())));
+ } else {
+ epgImageName << "_0";
+ epgPicAvailable = FileExists(*config.epgImagePath, epgImageName.str(), "jpg");
+ if (epgPicAvailable) {
+ headerIntTokens.insert(pair<string,int>("epgpicavailable", true));
+ headerStringTokens.insert(pair<string,string>("epgpicpath", *cString::sprintf("%s%s.jpg", *config.epgImagePath, epgImageName.str().c_str())));
+ } else {
+ headerIntTokens.insert(pair<string,int>("epgpicavailable", false));
+ headerStringTokens.insert(pair<string,string>("epgpicpath", ""));
+ }
+ }
+
+ DrawViewElement(veDetailHeader, &headerStringTokens, &headerIntTokens);
+ } else if (recording) {
+ string name = recording->Name() ? recording->Name() : "";
+ headerStringTokens.insert(pair<string,string>("name", name));
+
+ const cRecordingInfo *info = recording->Info();
+ if (info) {
+ headerStringTokens.insert(pair<string,string>("shorttext", info->ShortText() ? info->ShortText() : ""));
+ const cEvent *event = info->GetEvent();
+ if (event) {
+ string recDate = *(event->GetDateString());
+ string recTime = *(event->GetTimeString());
+ if (recDate.find("1970") != string::npos) {
+ time_t start = recording->Start();
+ recDate = *DateString(start);
+ recTime = *TimeString(start);
+ }
+ int duration = event->Duration() / 60;
+ int recDuration = recording->LengthInSeconds();
+ recDuration = (recDuration>0)?(recDuration / 60):0;
+ headerStringTokens.insert(pair<string,string>("date", recDate.c_str()));
+ headerStringTokens.insert(pair<string,string>("time", recTime.c_str()));
+ headerIntTokens.insert(pair<string,int>("duration", recDuration));
+ headerIntTokens.insert(pair<string,int>("durationevent", duration));
+ }
+ } else {
+ headerStringTokens.insert(pair<string,string>("shorttext", ""));
+ int recDuration = recording->LengthInSeconds();
+ recDuration = (recDuration>0)?(recDuration / 60):0;
+ headerStringTokens.insert(pair<string,string>("date", ""));
+ headerStringTokens.insert(pair<string,string>("time", ""));
+ headerIntTokens.insert(pair<string,int>("duration", recDuration));
+ headerIntTokens.insert(pair<string,int>("durationevent", 0));
+ }
+
+ string recImage = "";
+ string path = recording->FileName() ? recording->FileName() : "";
+ string extension = ".jpg";
+ if (FirstFileInFolder(path, extension, recImage)) {
+ headerIntTokens.insert(pair<string,int>("recimgavailable", true));
+ headerStringTokens.insert(pair<string,string>("recimgpath", *cString::sprintf("%s/%s", path.c_str(), recImage.c_str())));
+ } else {
+ headerIntTokens.insert(pair<string,int>("recimgavailable", false));
+ headerStringTokens.insert(pair<string,string>("recimgpath", ""));
+ }
+ DrawViewElement(veDetailHeader, &headerStringTokens, &headerIntTokens);
+ }
+}
+
+void cDisplayMenuDetailView::DrawScrollbar(void) {
+ map < string, string > scrollbarStringTokens;
+ map < string, int > scrollbarIntTokens;
+
+ int barTop = 0;
+ int barHeight = 0;
+ tabView->GetScrollbarPosition(barTop, barHeight);
+
+ scrollbarIntTokens.insert(pair<string,int>("height", barHeight));
+ scrollbarIntTokens.insert(pair<string,int>("offset", barTop));
+ ClearViewElement(veScrollbar);
+ DrawViewElement(veScrollbar, &scrollbarStringTokens, &scrollbarIntTokens);
+}
+
+void cDisplayMenuDetailView::DrawTabLabels(void) {
+ if (!ViewElementImplemented(veTabLabels)) {
+ return;
+ }
+ map < string, string > labelStringTokens;
+ map < string, int > labelIntTokens;
+ map < string, vector< map< string, string > > > labelLoopTokens;
+
+ vector< map< string, string > > tabLabels;
+ for (list<cTemplateViewTab*>::iterator it = activeTabs.begin(); it != activeTabs.end(); it++) {
+ cTemplateViewTab *tab = *it;
+ map< string, string > tabLabel;
+ tabLabel.insert(pair< string, string >("tabs[title]", tab->GetName()));
+ if (tab == currentTmplTab) {
+ tabLabel.insert(pair< string, string >("tabs[current]", "1"));
+ } else {
+ tabLabel.insert(pair< string, string >("tabs[current]", "0"));
+ }
+ tabLabels.push_back(tabLabel);
+ }
+ labelLoopTokens.insert(pair< string, vector< map< string, string > > >("tabs", tabLabels));
+
+ ClearViewElement(veTabLabels);
+ DrawViewElement(veTabLabels, &labelStringTokens, &labelIntTokens, &labelLoopTokens);
+}
+
+cTemplateViewTab *cDisplayMenuDetailView::GetPrevTab(void) {
+ if (atIt == activeTabs.begin()) {
+ atIt = activeTabs.end();
+ }
+ atIt--;
+ return *atIt;
+}
+
+cTemplateViewTab *cDisplayMenuDetailView::GetNextTab(void) {
+ atIt++;
+ if (atIt == activeTabs.end()) {
+ atIt = activeTabs.begin();
+ }
+ return *atIt;
+}
diff --git a/views/displaymenudetailview.h b/views/displaymenudetailview.h
new file mode 100644
index 0000000..c739a28
--- /dev/null
+++ b/views/displaymenudetailview.h
@@ -0,0 +1,50 @@
+#ifndef __DISPLAYMENUDETAILVIEW_H
+#define __DISPLAYMENUDETAILVIEW_H
+
+#include <list>
+#include "../libtemplate/template.h"
+#include "view.h"
+#include "displaymenutabview.h"
+
+class cDisplayMenuDetailView : public cView {
+private:
+ bool detailViewInit;
+ const cEvent *event;
+ const cRecording *recording;
+ const char *text;
+ cTemplateViewTab *currentTmplTab;
+ list<cTemplateViewTab*> activeTabs;
+ list<cTemplateViewTab*>::iterator atIt;
+ cDisplayMenuTabView *tabView;
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+ map < string, vector< map< string, string > > > loopTokens;
+ void SetTokens(void);
+ void SetScraperTokens(void);
+ void InitTabs(void);
+ bool LoadReruns(vector< map< string, string > > *reruns);
+ void LoadRecordingInformation(void);
+ void SetEpgPictures(int eventId);
+ void SetRecordingImages(const char *recPath);
+ string StripXmlTag(string &Line, const char *Tag);
+ int ReadSizeVdr(const char *strPath);
+ void DrawHeader(void);
+ void DrawScrollbar(void);
+ void DrawTabLabels(void);
+ cTemplateViewTab *GetPrevTab(void);
+ cTemplateViewTab *GetNextTab(void);
+public:
+ cDisplayMenuDetailView(cTemplateView *tmplDetailView);
+ virtual ~cDisplayMenuDetailView();
+ void SetEvent(const cEvent *event) { this->event = event; };
+ void SetRecording(const cRecording *recording) { this->recording = recording; };
+ void SetText(const char *text) { this->text = text; };
+ void Clear(void);
+ void Render(void);
+ void KeyLeft(void);
+ void KeyRight(void);
+ void KeyUp(void);
+ void KeyDown(void);
+};
+
+#endif //__DISPLAYMENUDETAILVIEW_H
diff --git a/views/displaymenuitemcurrentview.c b/views/displaymenuitemcurrentview.c
new file mode 100644
index 0000000..a615794
--- /dev/null
+++ b/views/displaymenuitemcurrentview.c
@@ -0,0 +1,561 @@
+#include "../services/scraper2vdr.h"
+#include "../libcore/helpers.h"
+#include "displaymenuitemcurrentview.h"
+
+
+cDisplayMenuItemCurrentView::cDisplayMenuItemCurrentView(cTemplateViewElement *tmplCurrent) : cView(tmplCurrent) {
+ delay = tmplItem->GetNumericParameter(ptDelay);
+ SetFadeTime(tmplItem->GetNumericParameter(ptFadeTime));
+}
+
+cDisplayMenuItemCurrentView::~cDisplayMenuItemCurrentView() {
+ CancelSave();
+}
+
+void cDisplayMenuItemCurrentView::SetPosMenuItem(cRect &pos) {
+ posMenuItem.SetX(pos.X());
+ posMenuItem.SetY(pos.Y());
+ posMenuItem.SetWidth(pos.Width());
+ posMenuItem.SetHeight(pos.Height());
+}
+
+void cDisplayMenuItemCurrentView::SetTokensPosMenuItem(void) {
+ intTokens.insert(pair<string,int>("menuitemx", posMenuItem.X()));
+ intTokens.insert(pair<string,int>("menuitemy", posMenuItem.Y()));
+ intTokens.insert(pair<string,int>("menuitemwidth", posMenuItem.Width()));
+ intTokens.insert(pair<string,int>("menuitemheight", posMenuItem.Height()));
+}
+
+void cDisplayMenuItemCurrentView::SetScraperPoster(const cEvent *event, const cRecording *recording) {
+ static cPlugin *pScraper = GetScraperPlugin();
+ if (!pScraper || (!event && !recording)) {
+ intTokens.insert(pair<string,int>("hasposter", false));
+ intTokens.insert(pair<string,int>("posterwidth", -1));
+ intTokens.insert(pair<string,int>("posterheight", -1));
+ stringTokens.insert(pair<string,string>("posterpath", ""));
+ return;
+ }
+
+ ScraperGetPoster call;
+ call.event = event;
+ call.recording = recording;
+ if (pScraper->Service("GetPoster", &call)) {
+ intTokens.insert(pair<string,int>("hasposter", true));
+ intTokens.insert(pair<string,int>("posterwidth", call.poster.width));
+ intTokens.insert(pair<string,int>("posterheight", call.poster.height));
+ stringTokens.insert(pair<string,string>("posterpath", call.poster.path));
+ } else {
+ intTokens.insert(pair<string,int>("hasposter", false));
+ intTokens.insert(pair<string,int>("posterwidth", -1));
+ intTokens.insert(pair<string,int>("posterheight", -1));
+ stringTokens.insert(pair<string,string>("posterpath", ""));
+ }
+}
+
+/*************************************************************
+* cDisplayMenuItemCurrentMainView
+*************************************************************/
+
+cDisplayMenuItemCurrentMainView::cDisplayMenuItemCurrentMainView(cTemplateViewElement *tmplCurrent, string number, string label, string icon)
+ : cDisplayMenuItemCurrentView(tmplCurrent) {
+ this->number = number;
+ this->label = label;
+ this->icon = icon;
+}
+
+cDisplayMenuItemCurrentMainView::~cDisplayMenuItemCurrentMainView() {
+}
+
+void cDisplayMenuItemCurrentMainView::Prepare(void) {
+}
+
+
+void cDisplayMenuItemCurrentMainView::Render(void) {
+ stringTokens.insert(pair<string,string>("number", number));
+ stringTokens.insert(pair<string,string>("label", label));
+ stringTokens.insert(pair<string,string>("icon", icon));
+ SetTokensPosMenuItem();
+ DrawViewElement(veMenuCurrentItemDetail, &stringTokens, &intTokens);
+}
+
+void cDisplayMenuItemCurrentMainView::Clear(void) {
+
+}
+
+void cDisplayMenuItemCurrentMainView::Action(void) {
+ SetInitFinished();
+ DoSleep(delay);
+ Render();
+ FadeIn();
+ DoFlush();
+ if (scrolling) {
+ DoSleep(scrollDelay);
+ if (scrollOrientation == orHorizontal) {
+ ScrollHorizontal(scrollingPix, scrollDelay, scrollSpeed, scrollMode);
+ } else {
+ ScrollVertical(scrollingPix, scrollDelay, scrollSpeed);
+ }
+ }
+}
+
+/*************************************************************
+* cDisplayMenuItemCurrentSchedulesView
+*************************************************************/
+
+cDisplayMenuItemCurrentSchedulesView::cDisplayMenuItemCurrentSchedulesView(cTemplateViewElement *tmplCurrent, const cEvent *event, const cChannel *channel, eTimerMatch timerMatch, eMenuCategory cat)
+ : cDisplayMenuItemCurrentView(tmplCurrent) {
+ this->event = event;
+ this->channel = channel;
+ this->timerMatch = timerMatch;
+ this->cat = cat;
+}
+
+cDisplayMenuItemCurrentSchedulesView::~cDisplayMenuItemCurrentSchedulesView() {
+}
+
+void cDisplayMenuItemCurrentSchedulesView::Prepare(void) {
+}
+
+
+void cDisplayMenuItemCurrentSchedulesView::Render(void) {
+ intTokens.insert(pair<string,int>("whatson", (cat == mcSchedule) ? true: false));
+ intTokens.insert(pair<string,int>("whatsonnow", (cat == mcScheduleNow) ? true: false));
+ intTokens.insert(pair<string,int>("whatsonnext", (cat == mcScheduleNext) ? true: false));
+ if (timerMatch == tmFull) {
+ intTokens.insert(pair<string,int>("timerpartitial", false));
+ intTokens.insert(pair<string,int>("timerfull", true));
+ } else if (timerMatch == tmPartial) {
+ intTokens.insert(pair<string,int>("timerpartitial", true));
+ intTokens.insert(pair<string,int>("timerfull", false));
+ } else {
+ intTokens.insert(pair<string,int>("timerpartitial", false));
+ intTokens.insert(pair<string,int>("timerfull", false));
+ }
+
+ if (event) {
+ stringTokens.insert(pair<string,string>("title", event->Title() ? event->Title() : ""));
+ stringTokens.insert(pair<string,string>("shorttext", event->ShortText() ? event->ShortText() : ""));
+ stringTokens.insert(pair<string,string>("description", event->Description() ? event->Description() : ""));
+ stringTokens.insert(pair<string,string>("start", *(event->GetTimeString())));
+ stringTokens.insert(pair<string,string>("stop", *(event->GetEndTimeString())));
+ stringTokens.insert(pair<string,string>("day", *WeekDayName(event->StartTime())));
+ stringTokens.insert(pair<string,string>("date", *ShortDateString(event->StartTime())));
+ bool isRunning = false;
+ time_t now = time(NULL);
+ if ((now >= event->StartTime()) && (now <= event->EndTime()))
+ isRunning = true;
+ intTokens.insert(pair<string,int>("running", isRunning));
+ if (isRunning) {
+ intTokens.insert(pair<string,int>("elapsed", (now - event->StartTime())/60));
+ } else {
+ intTokens.insert(pair<string,int>("elapsed", 0));
+ }
+ intTokens.insert(pair<string,int>("duration", event->Duration() / 60));
+ SetScraperPoster(event);
+ }
+ if (channel) {
+ stringTokens.insert(pair<string,string>("channelid", *(channel->GetChannelID().ToString())));
+ }
+
+ vector< map<string,string> > schedulesTokens;
+ if (cat == mcScheduleNow || cat == mcScheduleNext) {
+ ReadSchedules(&schedulesTokens);
+ }
+ map < string, vector< map< string, string > > > loopTokens;
+ loopTokens.insert(pair<string, vector< map< string, string > > >("schedule", schedulesTokens));
+ SetTokensPosMenuItem();
+ DrawViewElement(veMenuCurrentItemDetail, &stringTokens, &intTokens, &loopTokens);
+}
+
+void cDisplayMenuItemCurrentSchedulesView::Clear(void) {
+
+}
+
+void cDisplayMenuItemCurrentSchedulesView::Action(void) {
+ SetInitFinished();
+ DoSleep(delay);
+ Render();
+ FadeIn();
+ DoFlush();
+ if (scrolling) {
+ DoSleep(scrollDelay);
+ if (scrollOrientation == orHorizontal) {
+ ScrollHorizontal(scrollingPix, scrollDelay, scrollSpeed, scrollMode);
+ } else {
+ ScrollVertical(scrollingPix, scrollDelay, scrollSpeed);
+ }
+ }
+}
+
+void cDisplayMenuItemCurrentSchedulesView::ReadSchedules(vector< map<string,string> > *schedulesTokens) {
+ if (!event)
+ return;
+ const cSchedule *schedule = event->Schedule();
+ const cEvent *curEvent = event;
+ int num = 0;
+ for (; curEvent; curEvent = schedule->Events()->Next(curEvent)) {
+ if (num == 0) {
+ num++;
+ continue;
+ }
+ map<string,string> element;
+ element.insert(pair<string,string>("schedule[start]", *(curEvent->GetTimeString())));
+ element.insert(pair<string,string>("schedule[stop]", *(curEvent->GetEndTimeString())));
+ element.insert(pair<string,string>("schedule[title]", curEvent->Title() ? curEvent->Title() : ""));
+ element.insert(pair<string,string>("schedule[shorttext]", curEvent->ShortText() ? curEvent->ShortText() : ""));
+ schedulesTokens->push_back(element);
+ num++;
+ if (num > 10)
+ break;
+ }
+}
+
+/*************************************************************
+* cDisplayMenuItemCurrentChannelView
+*************************************************************/
+
+cDisplayMenuItemCurrentChannelView::cDisplayMenuItemCurrentChannelView(cTemplateViewElement *tmplCurrent, const cChannel *channel)
+ : cDisplayMenuItemCurrentView(tmplCurrent) {
+ this->channel = channel;
+}
+
+cDisplayMenuItemCurrentChannelView::~cDisplayMenuItemCurrentChannelView() {
+}
+
+void cDisplayMenuItemCurrentChannelView::Prepare(void) {
+}
+
+
+void cDisplayMenuItemCurrentChannelView::Render(void) {
+ if (!channel)
+ return;
+ //general channel information
+ intTokens.insert(pair<string,int>("number", channel->Number()));
+ intTokens.insert(pair<string,int>("transponder", channel->Transponder()));
+ intTokens.insert(pair<string,int>("frequency", channel->Frequency()));
+
+ stringTokens.insert(pair<string,string>("name", channel->Name() ? channel->Name() : ""));
+ stringTokens.insert(pair<string,string>("channelid", *(channel->GetChannelID().ToString())));
+
+ //Channel Source Information
+ const cSource *source = Sources.Get(channel->Source());
+ if (source) {
+ stringTokens.insert(pair<string,string>("source", *cSource::ToString(source->Code())));
+ stringTokens.insert(pair<string,string>("sourcedescription", source->Description() ? source->Description() : ""));
+ stringTokens.insert(pair<string,string>("source", *cSource::ToString(source->Code())));
+ intTokens.insert(pair<string,int>("isAtsc", source->IsAtsc(source->Code())));
+ intTokens.insert(pair<string,int>("isCable", source->IsCable(source->Code())));
+ intTokens.insert(pair<string,int>("isSat", source->IsSat(source->Code())));
+ intTokens.insert(pair<string,int>("isTerr", source->IsTerr(source->Code())));
+ }
+
+ //current schedule
+ cSchedulesLock schedulesLock;
+ const cSchedules *schedules = cSchedules::Schedules(schedulesLock);
+ const cSchedule *schedule = NULL;
+ schedule = schedules->GetSchedule(channel);
+ if (schedule) {
+ const cEvent *presentEvent = schedule->GetPresentEvent();
+ if (presentEvent) {
+ stringTokens.insert(pair<string,string>("presenteventtitle", presentEvent->Title() ? presentEvent->Title() : ""));
+ stringTokens.insert(pair<string,string>("presenteventshorttext", presentEvent->ShortText() ? presentEvent->ShortText() : ""));
+ stringTokens.insert(pair<string,string>("presenteventdescription", presentEvent->Description() ? presentEvent->Description() : ""));
+ stringTokens.insert(pair<string,string>("presenteventstart", *presentEvent->GetTimeString()));
+ stringTokens.insert(pair<string,string>("presenteventstop", *presentEvent->GetEndTimeString()));
+ stringTokens.insert(pair<string,string>("presenteventday", *WeekDayName(presentEvent->StartTime())));
+ stringTokens.insert(pair<string,string>("presenteventdate", *ShortDateString(presentEvent->StartTime())));
+ intTokens.insert(pair<string,int>("presenteventelapsed", (time(0) - presentEvent->StartTime())/60));
+ intTokens.insert(pair<string,int>("presenteventduration", presentEvent->Duration() / 60));
+ SetScraperPoster(presentEvent);
+ } else {
+ stringTokens.insert(pair<string,string>("presenteventtitle", ""));
+ stringTokens.insert(pair<string,string>("presenteventshorttext", ""));
+ stringTokens.insert(pair<string,string>("presenteventdescription", ""));
+ stringTokens.insert(pair<string,string>("presenteventstart", ""));
+ stringTokens.insert(pair<string,string>("presenteventstop", ""));
+ stringTokens.insert(pair<string,string>("presenteventday", ""));
+ stringTokens.insert(pair<string,string>("presenteventdate", ""));
+ intTokens.insert(pair<string,int>("presenteventelapsed", 0));
+ intTokens.insert(pair<string,int>("presenteventduration", 0));
+ }
+ const cList<cEvent> *events = schedule->Events();
+ bool inserted = false;
+ if (events && presentEvent) {
+ const cEvent *nextEvent = events->Next(presentEvent);
+ if (nextEvent) {
+ stringTokens.insert(pair<string,string>("nexteventtitle", nextEvent->Title() ? nextEvent->Title() : ""));
+ stringTokens.insert(pair<string,string>("nexteventshorttext", nextEvent->ShortText() ? nextEvent->ShortText() : ""));
+ stringTokens.insert(pair<string,string>("nexteventdescription", nextEvent->Description() ? nextEvent->Description() : ""));
+ stringTokens.insert(pair<string,string>("nexteventstart", *nextEvent->GetTimeString()));
+ stringTokens.insert(pair<string,string>("nexteventstop", *nextEvent->GetEndTimeString()));
+ stringTokens.insert(pair<string,string>("nexteventday", *WeekDayName(nextEvent->StartTime())));
+ stringTokens.insert(pair<string,string>("nexteventdate", *ShortDateString(nextEvent->StartTime())));
+ intTokens.insert(pair<string,int>("nexteventduration", nextEvent->Duration() / 60));
+ inserted = true;
+ }
+ }
+ if (!inserted) {
+ stringTokens.insert(pair<string,string>("nexteventtitle", ""));
+ stringTokens.insert(pair<string,string>("nexteventshorttext", ""));
+ stringTokens.insert(pair<string,string>("nexteventdescription", ""));
+ stringTokens.insert(pair<string,string>("nexteventstart", ""));
+ stringTokens.insert(pair<string,string>("nexteventstop", ""));
+ stringTokens.insert(pair<string,string>("nexteventday", ""));
+ stringTokens.insert(pair<string,string>("nexteventdate", ""));
+ intTokens.insert(pair<string,int>("nexteventduration", 0));
+ }
+ }
+
+ vector< map<string,string> > schedulesTokens;
+ ReadSchedules(&schedulesTokens);
+
+ map < string, vector< map< string, string > > > loopTokens;
+ loopTokens.insert(pair<string, vector< map< string, string > > >("schedule", schedulesTokens));
+ SetTokensPosMenuItem();
+ DrawViewElement(veMenuCurrentItemDetail, &stringTokens, &intTokens, &loopTokens);
+}
+
+void cDisplayMenuItemCurrentChannelView::Clear(void) {
+
+}
+
+void cDisplayMenuItemCurrentChannelView::Action(void) {
+ SetInitFinished();
+ DoSleep(delay);
+ Render();
+ FadeIn();
+ DoFlush();
+ if (scrolling) {
+ DoSleep(scrollDelay);
+ if (scrollOrientation == orHorizontal) {
+ ScrollHorizontal(scrollingPix, scrollDelay, scrollSpeed, scrollMode);
+ } else {
+ ScrollVertical(scrollingPix, scrollDelay, scrollSpeed);
+ }
+ }
+}
+
+void cDisplayMenuItemCurrentChannelView::ReadSchedules(vector< map<string,string> > *schedulesTokens) {
+ cSchedulesLock schedulesLock;
+ const cSchedules *schedules = cSchedules::Schedules(schedulesLock);
+ const cSchedule *schedule = NULL;
+ schedule = schedules->GetSchedule(channel);
+ if (!schedule) {
+ return;
+ }
+ const cEvent *curEvent = schedule->GetPresentEvent();
+ int num = 0;
+ for (; curEvent; curEvent = schedule->Events()->Next(curEvent)) {
+ if (num < 2) {
+ num++;
+ continue;
+ }
+ map<string,string> element;
+ element.insert(pair<string,string>("schedule[start]", *(curEvent->GetTimeString())));
+ element.insert(pair<string,string>("schedule[stop]", *(curEvent->GetEndTimeString())));
+ element.insert(pair<string,string>("schedule[title]", curEvent->Title() ? curEvent->Title() : ""));
+ element.insert(pair<string,string>("schedule[shorttext]", curEvent->ShortText() ? curEvent->ShortText() : ""));
+ schedulesTokens->push_back(element);
+ num++;
+ if (num > 11)
+ break;
+ }
+}
+
+/*************************************************************
+* cDisplayMenuItemCurrentTimerView
+*************************************************************/
+
+cDisplayMenuItemCurrentTimerView::cDisplayMenuItemCurrentTimerView(cTemplateViewElement *tmplCurrent, const cTimer *timer)
+ : cDisplayMenuItemCurrentView(tmplCurrent) {
+ this->timer = timer;
+}
+
+cDisplayMenuItemCurrentTimerView::~cDisplayMenuItemCurrentTimerView() {
+}
+
+void cDisplayMenuItemCurrentTimerView::Prepare(void) {
+}
+
+
+void cDisplayMenuItemCurrentTimerView::Render(void) {
+ if (!timer)
+ return;
+ intTokens.insert(pair<string,int>("flagactive", timer->HasFlags(tfActive)));
+ intTokens.insert(pair<string,int>("flaginstant", timer->HasFlags(tfInstant)));
+ intTokens.insert(pair<string,int>("flagvps", timer->HasFlags(tfVps)));
+ intTokens.insert(pair<string,int>("flagrecording", timer->Recording()));
+ intTokens.insert(pair<string,int>("flagpending", timer->Pending()));
+
+ const char *file = Setup.FoldersInTimerMenu ? NULL : strrchr(timer->File(), FOLDERDELIMCHAR);
+ if (file && strcmp(file + 1, TIMERMACRO_TITLE) && strcmp(file + 1, TIMERMACRO_EPISODE))
+ file++;
+ else
+ file = timer->File();
+ stringTokens.insert(pair<string,string>("title", file));
+ stringTokens.insert(pair<string,string>("timerstart", *cString::sprintf("%02d:%02d", timer->Start() / 100, timer->Start() % 100)));
+ stringTokens.insert(pair<string,string>("timerstop", *cString::sprintf("%02d:%02d", timer->Stop() / 100, timer->Stop() % 100)));
+
+ string day = "";
+ string dayName = "";
+ if (timer->WeekDays())
+ day = timer->PrintDay(0, timer->WeekDays(), false);
+ else if (timer->Day() - time(NULL) < 28 * SECSINDAY) {
+ day = itoa(timer->GetMDay(timer->Day()));
+ dayName = WeekDayName(timer->Day());
+ } else {
+ struct tm tm_r;
+ time_t Day = timer->Day();
+ localtime_r(&Day, &tm_r);
+ char buffer[16];
+ strftime(buffer, sizeof(buffer), "%Y%m%d", &tm_r);
+ day = buffer;
+ }
+ stringTokens.insert(pair<string,string>("day", day));
+ stringTokens.insert(pair<string,string>("dayname", dayName));
+
+ const cChannel *channel = timer->Channel();
+ if (channel) {
+ stringTokens.insert(pair<string,string>("channelname", channel->Name() ? channel->Name() : ""));
+ stringTokens.insert(pair<string,string>("channelid", *(channel->GetChannelID().ToString())));
+ intTokens.insert(pair<string,int>("channelnumber", channel->Number()));
+ } else {
+ stringTokens.insert(pair<string,string>("channelname", ""));
+ stringTokens.insert(pair<string,string>("channelid", ""));
+ intTokens.insert(pair<string,int>("channelnumber", 0));
+ }
+
+ const cEvent *event = timer->Event();
+ if (event) {
+ stringTokens.insert(pair<string,string>("eventtitle", event->Title() ? event->Title() : ""));
+ stringTokens.insert(pair<string,string>("eventstart", *event->GetTimeString()));
+ stringTokens.insert(pair<string,string>("eventstop", *event->GetEndTimeString()));
+ stringTokens.insert(pair<string,string>("eventshorttext", event->ShortText() ? event->ShortText() : ""));
+ stringTokens.insert(pair<string,string>("eventdescription", event->Description() ? event->Description() : ""));
+ SetScraperPoster(event);
+ } else {
+ stringTokens.insert(pair<string,string>("eventtitle", ""));
+ stringTokens.insert(pair<string,string>("eventtitle", ""));
+ stringTokens.insert(pair<string,string>("eventstop", ""));
+ stringTokens.insert(pair<string,string>("eventshorttext", ""));
+ stringTokens.insert(pair<string,string>("eventdescription", ""));
+ }
+ SetTokensPosMenuItem();
+ DrawViewElement(veMenuCurrentItemDetail, &stringTokens, &intTokens);
+}
+
+void cDisplayMenuItemCurrentTimerView::Clear(void) {
+
+}
+
+void cDisplayMenuItemCurrentTimerView::Action(void) {
+ SetInitFinished();
+ DoSleep(delay);
+ Render();
+ FadeIn();
+ DoFlush();
+ if (scrolling) {
+ DoSleep(scrollDelay);
+ if (scrollOrientation == orHorizontal) {
+ ScrollHorizontal(scrollingPix, scrollDelay, scrollSpeed, scrollMode);
+ } else {
+ ScrollVertical(scrollingPix, scrollDelay, scrollSpeed);
+ }
+ }
+}
+
+/*************************************************************
+* cDisplayMenuItemCurrentRecordingView
+*************************************************************/
+
+cDisplayMenuItemCurrentRecordingView::cDisplayMenuItemCurrentRecordingView(cTemplateViewElement *tmplCurrent, const cRecording *recording, int level, int total, int newRecs)
+ : cDisplayMenuItemCurrentView(tmplCurrent) {
+ this->recording = recording;
+ this->level = level;
+ this->total = total;
+ this->newRecs = newRecs;
+}
+
+cDisplayMenuItemCurrentRecordingView::~cDisplayMenuItemCurrentRecordingView() {
+}
+
+void cDisplayMenuItemCurrentRecordingView::Prepare(void) {
+}
+
+
+void cDisplayMenuItemCurrentRecordingView::Render(void) {
+ if (!recording)
+ return;
+ bool isFolder = (total > 0) ? true : false;
+ intTokens.insert(pair<string,int>("folder", isFolder));
+
+ string name = recording->Name() ? recording->Name() : "";
+ string buffer = "";
+ try {
+ vector<string> tokens;
+ istringstream f(name.c_str());
+ string s;
+ while (getline(f, s, FOLDERDELIMCHAR)) {
+ tokens.push_back(s);
+ }
+ buffer = tokens.at(level);
+ if (!isFolder && recording->IsEdited()) {
+ buffer = buffer.substr(1);
+ }
+ } catch (...) {
+ buffer = name.c_str();
+ }
+ stringTokens.insert(pair<string,string>("name", buffer.c_str()));
+ intTokens.insert(pair<string,int>("new", recording->IsNew()));
+ intTokens.insert(pair<string,int>("newrecordingsfolder", newRecs));
+ intTokens.insert(pair<string,int>("numrecordingsfolder", total));
+ intTokens.insert(pair<string,int>("cutted", recording->IsEdited()));
+
+ SetScraperPoster(NULL, recording);
+
+ const cRecordingInfo *info = recording->Info();
+ if (!info) return;
+
+ stringTokens.insert(pair<string,string>("shorttext", info->ShortText() ? info->ShortText() : ""));
+ stringTokens.insert(pair<string,string>("description", info->Description() ? info->Description() : ""));
+
+ const cEvent *event = info->GetEvent();
+ if (!event) return;
+
+ string recDate = *(event->GetDateString());
+ string recTime = *(event->GetTimeString());
+ if (recDate.find("1970") != string::npos) {
+ time_t start = recording->Start();
+ recDate = *DateString(start);
+ recTime = *TimeString(start);
+ }
+ int duration = event->Duration() / 60;
+ int recDuration = recording->LengthInSeconds();
+ recDuration = (recDuration>0)?(recDuration / 60):0;
+ stringTokens.insert(pair<string,string>("date", recDate.c_str()));
+ stringTokens.insert(pair<string,string>("time", recTime.c_str()));
+ intTokens.insert(pair<string,int>("duration", recDuration));
+ intTokens.insert(pair<string,int>("durationevent", duration));
+ SetTokensPosMenuItem();
+ DrawViewElement(veMenuCurrentItemDetail, &stringTokens, &intTokens);
+}
+
+void cDisplayMenuItemCurrentRecordingView::Clear(void) {
+
+}
+
+void cDisplayMenuItemCurrentRecordingView::Action(void) {
+ SetInitFinished();
+ DoSleep(delay);
+ Render();
+ FadeIn();
+ DoFlush();
+ if (scrolling) {
+ DoSleep(scrollDelay);
+ if (scrollOrientation == orHorizontal) {
+ ScrollHorizontal(scrollingPix, scrollDelay, scrollSpeed, scrollMode);
+ } else {
+ ScrollVertical(scrollingPix, scrollDelay, scrollSpeed);
+ }
+ }
+}
diff --git a/views/displaymenuitemcurrentview.h b/views/displaymenuitemcurrentview.h
new file mode 100644
index 0000000..12f31e3
--- /dev/null
+++ b/views/displaymenuitemcurrentview.h
@@ -0,0 +1,94 @@
+#ifndef __DISPLAYMENUITEMCURRENTVIEW_H
+#define __DISPLAYMENUITEMCURRENTVIEW_H
+
+#include "../libtemplate/template.h"
+#include "view.h"
+
+class cDisplayMenuItemCurrentView : public cView {
+private:
+protected:
+ int delay;
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+ cRect posMenuItem;
+ void SetTokensPosMenuItem(void);
+ void SetScraperPoster(const cEvent *event, const cRecording *recording=NULL);
+public:
+ cDisplayMenuItemCurrentView(cTemplateViewElement *tmplCurrent);
+ virtual ~cDisplayMenuItemCurrentView();
+ void SetPosMenuItem(cRect &pos);
+ virtual void Prepare(void) {};
+ virtual void Render(void) {};
+ virtual void Clear(void) {};
+};
+
+class cDisplayMenuItemCurrentMainView: public cDisplayMenuItemCurrentView {
+private:
+ string number;
+ string label;
+ string icon;
+ void Action(void);
+public:
+ cDisplayMenuItemCurrentMainView(cTemplateViewElement *tmplCurrent, string number, string label, string icon);
+ virtual ~cDisplayMenuItemCurrentMainView();
+ void Prepare(void);
+ void Render(void);
+ void Clear(void);
+};
+
+class cDisplayMenuItemCurrentSchedulesView: public cDisplayMenuItemCurrentView {
+private:
+ const cEvent *event;
+ const cChannel *channel;
+ eTimerMatch timerMatch;
+ eMenuCategory cat;
+ void Action(void);
+ void ReadSchedules(vector< map<string,string> > *schedulesTokens);
+public:
+ cDisplayMenuItemCurrentSchedulesView(cTemplateViewElement *tmplCurrent, const cEvent *event, const cChannel *channel, eTimerMatch timerMatch, eMenuCategory cat);
+ virtual ~cDisplayMenuItemCurrentSchedulesView();
+ void Prepare(void);
+ void Render(void);
+ void Clear(void);
+};
+
+class cDisplayMenuItemCurrentChannelView: public cDisplayMenuItemCurrentView {
+private:
+ const cChannel *channel;
+ void Action(void);
+ void ReadSchedules(vector< map<string,string> > *schedulesTokens);
+public:
+ cDisplayMenuItemCurrentChannelView(cTemplateViewElement *tmplCurrent, const cChannel *channel);
+ virtual ~cDisplayMenuItemCurrentChannelView();
+ void Prepare(void);
+ void Render(void);
+ void Clear(void);
+};
+
+class cDisplayMenuItemCurrentTimerView: public cDisplayMenuItemCurrentView {
+private:
+ const cTimer *timer;
+ void Action(void);
+public:
+ cDisplayMenuItemCurrentTimerView(cTemplateViewElement *tmplCurrent, const cTimer *timer);
+ virtual ~cDisplayMenuItemCurrentTimerView();
+ void Prepare(void);
+ void Render(void);
+ void Clear(void);
+};
+
+class cDisplayMenuItemCurrentRecordingView: public cDisplayMenuItemCurrentView {
+private:
+ const cRecording *recording;
+ int level;
+ int total;
+ int newRecs;
+ void Action(void);
+public:
+ cDisplayMenuItemCurrentRecordingView(cTemplateViewElement *tmplCurrent, const cRecording *recording, int level, int total, int newRecs);
+ virtual ~cDisplayMenuItemCurrentRecordingView();
+ void Prepare(void);
+ void Render(void);
+ void Clear(void);
+};
+#endif //__DISPLAYMENUITEMCURRENTVIEW_H
diff --git a/views/displaymenuitemview.c b/views/displaymenuitemview.c
new file mode 100644
index 0000000..b103cf3
--- /dev/null
+++ b/views/displaymenuitemview.c
@@ -0,0 +1,731 @@
+#include "displaymenuitemview.h"
+#include "../services/scraper2vdr.h"
+#include "../config.h"
+#include "../libcore/helpers.h"
+#include <sstream>
+#include <algorithm>
+
+/*************************************************************
+* cDisplayMenuItemView
+*************************************************************/
+
+cDisplayMenuItemView::cDisplayMenuItemView(cTemplateViewList *tmplList, bool current, bool selectable) : cViewListItem(tmplList->GetListElement()) {
+ this->tmplList = tmplList;
+ this->current = current;
+ this->selectable = selectable;
+ itemInit = true;
+ dirty = true;
+ num = 0;
+ currentView = NULL;
+}
+
+cDisplayMenuItemView::~cDisplayMenuItemView() {
+ if (currentView)
+ delete currentView;
+ CancelSave();
+}
+
+void cDisplayMenuItemView::SetCurrent(bool cur) {
+ current = cur;
+ intTokens.erase("current");
+ intTokens.insert(pair<string,int>("current", current));
+ dirty = true;
+};
+
+
+void cDisplayMenuItemView::ArrangeContainer(void) {
+ if (pos > -1)
+ return;
+ SetInitFinished();
+ pos = num;
+ numTotal = tmplList->GetNumericParameter(ptNumElements);
+ container.SetX(tmplList->GetNumericParameter(ptX));
+ container.SetY(tmplList->GetNumericParameter(ptY));
+ container.SetWidth(tmplList->GetNumericParameter(ptWidth));
+ container.SetHeight(tmplList->GetNumericParameter(ptHeight));
+ align = tmplList->GetNumericParameter(ptAlign);
+ listOrientation = tmplList->GetNumericParameter(ptOrientation);
+}
+
+void cDisplayMenuItemView::Clear(void) {
+ ClearListItem();
+ if (currentView) {
+ delete currentView;
+ currentView = NULL;
+ }
+}
+
+void cDisplayMenuItemView::PrepareScrolling(void) {
+ currentlyScrolling = true;
+ ClearListItem();
+ DrawListItem(&stringTokens, &intTokens);
+}
+
+void cDisplayMenuItemView::EndScrolling(void) {
+ const cPoint p(0,0);
+ SetDrawPortPoint(scrollingPix, p);
+ currentlyScrolling = false;
+ ClearListItem();
+ DrawListItem(&stringTokens, &intTokens);
+}
+
+void cDisplayMenuItemView::Action(void) {
+ if (scrolling) {
+ DoSleep(scrollDelay);
+ PrepareScrolling();
+ if (scrollOrientation == orHorizontal) {
+ ScrollHorizontal(scrollingPix, scrollDelay, scrollSpeed, scrollMode);
+ } else {
+ ScrollVertical(scrollingPix, scrollDelay, scrollSpeed);
+ }
+ }
+}
+
+void cDisplayMenuItemView::Stop(void) {
+ if (Running()) {
+ CancelSave();
+ EndScrolling();
+ }
+}
+
+
+void cDisplayMenuItemView::Debug(void) {
+ esyslog("skindesigner: current %d, selectable %d", current, selectable);
+ esyslog("skindesigner: pos %d, numTotal %d", pos, numTotal);
+ esyslog("skindesigner: container x = %d, y = %d, width = %d, height = %d", container.X(), container.Y(), container.Width(), container.Height());
+}
+
+/*************************************************************
+* cDisplayMenuItemDefaultView
+*************************************************************/
+
+cDisplayMenuItemDefaultView::cDisplayMenuItemDefaultView(cTemplateViewList *tmplList, string *tabTexts, int *tabs, int *tabWidths, bool current, bool selectable)
+ : cDisplayMenuItemView(tmplList, current, selectable) {
+ this->tabTexts = tabTexts;
+ this->tabs = tabs;
+ this->tabWidths = tabWidths;
+ maxTabs = cSkinDisplayMenu::MaxTabs;
+}
+
+cDisplayMenuItemDefaultView::~cDisplayMenuItemDefaultView() {
+ delete[] tabTexts;
+}
+
+void cDisplayMenuItemDefaultView::SetTabTexts(string *tabTexts) {
+ delete[] this->tabTexts;
+ this->tabTexts = tabTexts;
+}
+
+void cDisplayMenuItemDefaultView::SetTokens(void) {
+ stringTokens.clear();
+ intTokens.clear();
+ for (int i=0; i<maxTabs; i++) {
+ stringstream name;
+ name << "column" << (i+1);
+ stringstream nameUsed;
+ nameUsed << name.str() << "set";
+ stringstream nameX;
+ nameX << name.str() << "x";
+ stringstream nameWidth;
+ nameWidth << name.str() << "width";
+ stringTokens.insert(pair<string,string>(name.str(), tabTexts[i]));
+ if (i>0)
+ intTokens.insert(pair<string,int>(nameUsed.str(), (tabTexts[i].size() > 0) ? 1 : 0 ));
+ intTokens.insert(pair<string,int>(nameX.str(), tabs[i]));
+ intTokens.insert(pair<string,int>(nameWidth.str(), tabWidths[i]));
+ }
+ intTokens.insert(pair<string,int>("current", current));
+ intTokens.insert(pair<string,int>("separator", !selectable));
+}
+
+void cDisplayMenuItemDefaultView::Prepare(void) {
+ ArrangeContainer();
+}
+
+
+void cDisplayMenuItemDefaultView::Render(void) {
+ DrawListItem(&stringTokens, &intTokens);
+ dirty = false;
+}
+
+void cDisplayMenuItemDefaultView::Debug(void) {
+ esyslog("skindesigner: Default Menu Item ---------------");
+ cDisplayMenuItemView::Debug();
+ for (int i=0; i<maxTabs; i++) {
+ esyslog("skindesigner: tab %d: text: %s, x: %d", i, tabTexts[i].c_str(), tabs[i]);
+ }
+}
+
+/*************************************************************
+* Private Functions
+*************************************************************/
+
+
+/*************************************************************
+* cDisplayMenuItemMainView
+*************************************************************/
+
+cDisplayMenuItemMainView::cDisplayMenuItemMainView(cTemplateViewList *tmplList, string itemText, bool current, bool selectable)
+ : cDisplayMenuItemView(tmplList, current, selectable) {
+ text = itemText;
+ number = "";
+ label = "";
+ icon = "";
+}
+
+cDisplayMenuItemMainView::~cDisplayMenuItemMainView() {
+}
+
+void cDisplayMenuItemMainView::SetTokens(void) {
+ if (!itemInit)
+ return;
+ itemInit = false;
+ stringTokens.insert(pair<string,string>("number", number));
+ stringTokens.insert(pair<string,string>("label", label));
+ stringTokens.insert(pair<string,string>("icon", icon));
+
+ intTokens.insert(pair<string,int>("current", current));
+ intTokens.insert(pair<string,int>("separator", !selectable));
+}
+
+void cDisplayMenuItemMainView::Prepare(void) {
+ ArrangeContainer();
+ SplitMenuText();
+ icon = imgCache->GetIconName(label);
+}
+
+
+void cDisplayMenuItemMainView::Render(void) {
+
+ cRect pos = DrawListItem(&stringTokens, &intTokens);
+
+ if (current) {
+ cTemplateViewElement *tmplCurrent = tmplList->GetListElementCurrent();
+ if (tmplCurrent) {
+ currentView = new cDisplayMenuItemCurrentMainView(tmplCurrent, number, label, icon);
+ currentView->SetPosMenuItem(pos);
+ currentView->Start();
+ }
+ }
+
+ dirty = false;
+}
+
+void cDisplayMenuItemMainView::Debug(void) {
+ esyslog("skindesigner: Main Menu Item ---------------");
+ cDisplayMenuItemView::Debug();
+ esyslog("skindesigner: item Text: %s", text.c_str());
+ esyslog("skindesigner: item Number: %s, Label: %s", number.c_str(), label.c_str());
+ esyslog("skindesigner: Icon: %s", icon.c_str());
+}
+
+/*************************************************************
+* Private Functions
+*************************************************************/
+
+void cDisplayMenuItemMainView::SplitMenuText(void) {
+ string textPlain = skipspace(text.c_str());
+ bool found = false;
+ bool doBreak = false;
+ size_t i = 0;
+ for (; i < textPlain.length(); i++) {
+ char s = textPlain.at(i);
+ if (i==0) {
+ //if text directly starts with nonnumeric, break
+ if (!(s >= '0' && s <= '9')) {
+ break;
+ }
+ }
+ if (found) {
+ if (!(s >= '0' && s <= '9')) {
+ doBreak = true;
+ }
+ }
+ if (s >= '0' && s <= '9') {
+ found = true;
+ }
+ if (doBreak)
+ break;
+ if (i>4)
+ break;
+ }
+ if (found) {
+ number = skipspace(textPlain.substr(0,i).c_str());
+ label = skipspace(textPlain.substr(i).c_str());
+ } else {
+ number = "";
+ label = textPlain.c_str();
+ }
+}
+
+/*************************************************************
+* cDisplayMenuItemSchedulesView
+*************************************************************/
+
+cDisplayMenuItemSchedulesView::cDisplayMenuItemSchedulesView(cTemplateViewList *tmplList, const cEvent *event,
+ const cChannel *channel, eTimerMatch timerMatch,
+ eMenuCategory cat, bool current, bool selectable)
+ : cDisplayMenuItemView(tmplList, current, selectable) {
+ this->event = event;
+ this->channel = channel;
+ this->timerMatch = timerMatch;
+ this->cat = cat;
+}
+
+cDisplayMenuItemSchedulesView::~cDisplayMenuItemSchedulesView() {
+}
+
+void cDisplayMenuItemSchedulesView::SetTokens(void) {
+ if (!itemInit)
+ return;
+ itemInit = false;
+ intTokens.insert(pair<string,int>("current", current));
+ intTokens.insert(pair<string,int>("separator", !selectable));
+ intTokens.insert(pair<string,int>("whatson", (cat == mcSchedule) ? true: false));
+ intTokens.insert(pair<string,int>("whatsonnow", (cat == mcScheduleNow) ? true: false));
+ intTokens.insert(pair<string,int>("whatsonnext", (cat == mcScheduleNext) ? true: false));
+ if (timerMatch == tmFull) {
+ intTokens.insert(pair<string,int>("timerpartitial", false));
+ intTokens.insert(pair<string,int>("timerfull", true));
+ } else if (timerMatch == tmPartial) {
+ intTokens.insert(pair<string,int>("timerpartitial", true));
+ intTokens.insert(pair<string,int>("timerfull", false));
+ } else {
+ intTokens.insert(pair<string,int>("timerpartitial", false));
+ intTokens.insert(pair<string,int>("timerfull", false));
+ }
+
+ if (event) {
+ if (selectable) {
+ stringTokens.insert(pair<string,string>("title", event->Title() ? event->Title() : ""));
+ stringTokens.insert(pair<string,string>("shorttext", event->ShortText() ? event->ShortText() : ""));
+ stringTokens.insert(pair<string,string>("start", *(event->GetTimeString())));
+ stringTokens.insert(pair<string,string>("stop", *(event->GetEndTimeString())));
+ stringTokens.insert(pair<string,string>("day", *WeekDayName(event->StartTime())));
+ stringTokens.insert(pair<string,string>("date", *ShortDateString(event->StartTime())));
+ bool isRunning = false;
+ time_t now = time(NULL);
+ if ((now >= event->StartTime()) && (now <= event->EndTime()))
+ isRunning = true;
+ intTokens.insert(pair<string,int>("running", isRunning));
+ if (isRunning) {
+ intTokens.insert(pair<string,int>("elapsed", (now - event->StartTime())/60));
+ } else {
+ intTokens.insert(pair<string,int>("elapsed", 0));
+ }
+ intTokens.insert(pair<string,int>("duration", event->Duration() / 60));
+ } else {
+ stringTokens.insert(pair<string,string>("title", event->Title() ? ParseSeparator(event->Title()) : ""));
+ }
+ }
+ if (channel) {
+ stringTokens.insert(pair<string,string>("channelid", *(channel->GetChannelID().ToString())));
+ if (!event && !selectable) {
+ stringTokens.insert(pair<string,string>("title", channel->Name() ? ParseSeparator(channel->Name()) : ""));
+ }
+ }
+}
+
+
+void cDisplayMenuItemSchedulesView::Prepare(void) {
+ ArrangeContainer();
+}
+
+void cDisplayMenuItemSchedulesView::Render(void) {
+
+ DrawListItem(&stringTokens, &intTokens);
+
+ if (current) {
+ cTemplateViewElement *tmplCurrent = tmplList->GetListElementCurrent();
+ if (tmplCurrent) {
+ currentView = new cDisplayMenuItemCurrentSchedulesView(tmplCurrent, event, channel, timerMatch, cat);
+ currentView->Start();
+ }
+ }
+
+ dirty = false;
+}
+
+void cDisplayMenuItemSchedulesView::Debug(void) {
+ esyslog("skindesigner: Schedules Menu Item ---------------");
+ cDisplayMenuItemView::Debug();
+ esyslog("skindesigner: Event: %s", event ? event->Title() : "Event is NULL");
+}
+
+/*************************************************************
+* Private Functions
+*************************************************************/
+
+string cDisplayMenuItemSchedulesView::ParseSeparator(string sep) {
+ string separator = sep;
+ try {
+ if (separator.find_first_not_of("-") > 0)
+ separator.erase(0, separator.find_first_not_of("-")+1);
+ if (separator.find_last_not_of("-") != string::npos)
+ separator.erase(separator.find_last_not_of("-")+1);
+ } catch (...) {}
+ return separator;
+}
+
+/*************************************************************
+* cDisplayMenuItemChannelsView
+*************************************************************/
+
+cDisplayMenuItemChannelsView::cDisplayMenuItemChannelsView(cTemplateViewList *tmplList, const cChannel *channel,
+ bool withProvider, bool current, bool selectable)
+ : cDisplayMenuItemView(tmplList, current, selectable) {
+ this->channel = channel;
+ this->withProvider = withProvider;
+}
+
+cDisplayMenuItemChannelsView::~cDisplayMenuItemChannelsView() {
+}
+
+void cDisplayMenuItemChannelsView::SetTokens(void) {
+ if (!itemInit)
+ return;
+ itemInit = false;
+ if (!channel)
+ return;
+ //general channel information
+ intTokens.insert(pair<string,int>("current", current));
+ intTokens.insert(pair<string,int>("separator", !selectable));
+ intTokens.insert(pair<string,int>("number", channel->Number()));
+ intTokens.insert(pair<string,int>("transponder", channel->Transponder()));
+ intTokens.insert(pair<string,int>("frequency", channel->Frequency()));
+
+ stringTokens.insert(pair<string,string>("name", channel->Name() ? channel->Name() : ""));
+ stringTokens.insert(pair<string,string>("channelid", *(channel->GetChannelID().ToString())));
+
+ //Channel Source Information
+ const cSource *source = Sources.Get(channel->Source());
+ if (source) {
+ stringTokens.insert(pair<string,string>("source", *cSource::ToString(source->Code())));
+ stringTokens.insert(pair<string,string>("sourcedescription", source->Description() ? source->Description() : ""));
+ stringTokens.insert(pair<string,string>("source", *cSource::ToString(source->Code())));
+ intTokens.insert(pair<string,int>("isAtsc", source->IsAtsc(source->Code())));
+ intTokens.insert(pair<string,int>("isCable", source->IsCable(source->Code())));
+ intTokens.insert(pair<string,int>("isSat", source->IsSat(source->Code())));
+ intTokens.insert(pair<string,int>("isTerr", source->IsTerr(source->Code())));
+ }
+
+ //current schedule
+ cSchedulesLock schedulesLock;
+ const cSchedules *schedules = cSchedules::Schedules(schedulesLock);
+ const cSchedule *schedule = NULL;
+ schedule = schedules->GetSchedule(channel);
+ bool inserted = false;
+ if (schedule) {
+ const cEvent *presentEvent = schedule->GetPresentEvent();
+ if (presentEvent) {
+ stringTokens.insert(pair<string,string>("presenteventtitle", presentEvent->Title() ? presentEvent->Title() : ""));
+ stringTokens.insert(pair<string,string>("presenteventstart", *presentEvent->GetTimeString()));
+ stringTokens.insert(pair<string,string>("presenteventstop", *presentEvent->GetEndTimeString()));
+ inserted = true;
+ }
+ }
+ if (!inserted) {
+ stringTokens.insert(pair<string,string>("presenteventtitle", ""));
+ stringTokens.insert(pair<string,string>("presenteventstart", ""));
+ stringTokens.insert(pair<string,string>("presenteventstop", ""));
+ }
+}
+
+
+void cDisplayMenuItemChannelsView::Prepare(void) {
+ ArrangeContainer();
+}
+
+void cDisplayMenuItemChannelsView::Render(void) {
+
+ DrawListItem(&stringTokens, &intTokens);
+
+ if (current) {
+ cTemplateViewElement *tmplCurrent = tmplList->GetListElementCurrent();
+ if (tmplCurrent) {
+ currentView = new cDisplayMenuItemCurrentChannelView(tmplCurrent, channel);
+ currentView->Start();
+ }
+ }
+
+ dirty = false;
+}
+
+void cDisplayMenuItemChannelsView::Debug(void) {
+ esyslog("skindesigner: Channels Menu Item ---------------");
+ cDisplayMenuItemView::Debug();
+ esyslog("skindesigner: Channel: %s", channel ? channel->Name() : "Channel is NULL");
+}
+
+/*************************************************************
+* Private Functions
+*************************************************************/
+
+/*************************************************************
+* cDisplayMenuItemTimersView
+*************************************************************/
+
+cDisplayMenuItemTimersView::cDisplayMenuItemTimersView(cTemplateViewList *tmplList, const cTimer *timer, bool current, bool selectable)
+ : cDisplayMenuItemView(tmplList, current, selectable) {
+ this->timer = timer;
+}
+
+cDisplayMenuItemTimersView::~cDisplayMenuItemTimersView() {
+}
+
+void cDisplayMenuItemTimersView::SetTokens(void) {
+ if (!timer)
+ return;
+ if (!itemInit) {
+ intTokens.erase("flagactive");
+ intTokens.insert(pair<string,int>("flagactive", timer->HasFlags(tfActive)));
+ return;
+ }
+ itemInit = false;
+
+ intTokens.insert(pair<string,int>("current", current));
+ intTokens.insert(pair<string,int>("flagactive", timer->HasFlags(tfActive)));
+ intTokens.insert(pair<string,int>("flaginstant", timer->HasFlags(tfInstant)));
+ intTokens.insert(pair<string,int>("flagvps", timer->HasFlags(tfVps)));
+ intTokens.insert(pair<string,int>("flagrecording", timer->Recording()));
+ intTokens.insert(pair<string,int>("flagpending", timer->Pending()));
+
+
+ const char *file = Setup.FoldersInTimerMenu ? NULL : strrchr(timer->File(), FOLDERDELIMCHAR);
+ if (file && strcmp(file + 1, TIMERMACRO_TITLE) && strcmp(file + 1, TIMERMACRO_EPISODE))
+ file++;
+ else
+ file = timer->File();
+ stringTokens.insert(pair<string,string>("title", file));
+ stringTokens.insert(pair<string,string>("timerstart", *cString::sprintf("%02d:%02d", timer->Start() / 100, timer->Start() % 100)));
+ stringTokens.insert(pair<string,string>("timerstop", *cString::sprintf("%02d:%02d", timer->Stop() / 100, timer->Stop() % 100)));
+
+ string day = "";
+ string dayName = "";
+ if (timer->WeekDays())
+ day = timer->PrintDay(0, timer->WeekDays(), false);
+ else if (timer->Day() - time(NULL) < 28 * SECSINDAY) {
+ day = itoa(timer->GetMDay(timer->Day()));
+ dayName = WeekDayName(timer->Day());
+ } else {
+ struct tm tm_r;
+ time_t Day = timer->Day();
+ localtime_r(&Day, &tm_r);
+ char buffer[16];
+ strftime(buffer, sizeof(buffer), "%Y%m%d", &tm_r);
+ day = buffer;
+ }
+ stringTokens.insert(pair<string,string>("day", day));
+ stringTokens.insert(pair<string,string>("dayname", dayName));
+
+ const cChannel *channel = timer->Channel();
+ if (channel) {
+ stringTokens.insert(pair<string,string>("channelname", channel->Name() ? channel->Name() : ""));
+ stringTokens.insert(pair<string,string>("channelid", *(channel->GetChannelID().ToString())));
+ intTokens.insert(pair<string,int>("channelnumber", channel->Number()));
+ } else {
+ stringTokens.insert(pair<string,string>("channelname", ""));
+ stringTokens.insert(pair<string,string>("channelid", ""));
+ intTokens.insert(pair<string,int>("channelnumber", 0));
+ }
+
+ const cEvent *event = timer->Event();
+ if (event) {
+ stringTokens.insert(pair<string,string>("eventtitle", event->Title() ? event->Title() : ""));
+ stringTokens.insert(pair<string,string>("eventstart", *event->GetTimeString()));
+ stringTokens.insert(pair<string,string>("eventstop", *event->GetEndTimeString()));
+ } else {
+ stringTokens.insert(pair<string,string>("eventtitle", ""));
+ stringTokens.insert(pair<string,string>("eventtitle", ""));
+ stringTokens.insert(pair<string,string>("eventstop", ""));
+ }
+}
+
+
+void cDisplayMenuItemTimersView::Prepare(void) {
+ ArrangeContainer();
+}
+
+void cDisplayMenuItemTimersView::Render(void) {
+
+ DrawListItem(&stringTokens, &intTokens);
+
+ if (current) {
+ cTemplateViewElement *tmplCurrent = tmplList->GetListElementCurrent();
+ if (tmplCurrent) {
+ currentView = new cDisplayMenuItemCurrentTimerView(tmplCurrent, timer);
+ currentView->Start();
+ }
+ }
+
+ dirty = false;
+}
+
+void cDisplayMenuItemTimersView::Debug(void) {
+ esyslog("skindesigner: Timers Menu Item ---------------");
+ cDisplayMenuItemView::Debug();
+ esyslog("skindesigner: Timer: %s", timer ? *(timer->ToDescr()) : "Timer is NULL");
+}
+
+/*************************************************************
+* Private Functions
+*************************************************************/
+
+
+/*************************************************************
+* cDisplayMenuItemRecordingView
+*************************************************************/
+
+cDisplayMenuItemRecordingView::cDisplayMenuItemRecordingView(cTemplateViewList *tmplList, const cRecording *recording, int level, int total, int newRecs, bool current, bool selectable)
+ : cDisplayMenuItemView(tmplList, current, selectable) {
+ this->recording = recording;
+ this->level = level;
+ this->total = total;
+ this->newRecs = newRecs;
+}
+
+cDisplayMenuItemRecordingView::~cDisplayMenuItemRecordingView() {
+}
+
+void cDisplayMenuItemRecordingView::SetTokens(void) {
+ if (!itemInit) return;
+ itemInit = false;
+ if (!recording) return;
+
+ intTokens.insert(pair<string,int>("current", current));
+ bool isFolder = (total > 0) ? true : false;
+ intTokens.insert(pair<string,int>("folder", isFolder));
+
+ string name = recording->Name() ? recording->Name() : "";
+ string buffer = "";
+ try {
+ vector<string> tokens;
+ istringstream f(name.c_str());
+ string s;
+ while (getline(f, s, FOLDERDELIMCHAR)) {
+ tokens.push_back(s);
+ }
+ buffer = tokens.at(level);
+ if (!isFolder && recording->IsEdited()) {
+ buffer = buffer.substr(1);
+ }
+ } catch (...) {
+ buffer = name.c_str();
+ }
+ stringTokens.insert(pair<string,string>("name", buffer.c_str()));
+ intTokens.insert(pair<string,int>("new", recording->IsNew()));
+ intTokens.insert(pair<string,int>("newrecordingsfolder", newRecs));
+ intTokens.insert(pair<string,int>("numrecordingsfolder", total));
+ intTokens.insert(pair<string,int>("cutted", recording->IsEdited()));
+
+ const cEvent *event = NULL;
+ const cRecordingInfo *info = recording->Info();
+ if (!info) return;
+ event = info->GetEvent();
+ if (!event) return;
+
+ string recDate = *(event->GetDateString());
+ string recTime = *(event->GetTimeString());
+ if (recDate.find("1970") != string::npos) {
+ time_t start = recording->Start();
+ recDate = *DateString(start);
+ recTime = *TimeString(start);
+ }
+ int duration = event->Duration() / 60;
+ int recDuration = recording->LengthInSeconds();
+ recDuration = (recDuration>0)?(recDuration / 60):0;
+ stringTokens.insert(pair<string,string>("date", recDate.c_str()));
+ stringTokens.insert(pair<string,string>("time", recTime.c_str()));
+ intTokens.insert(pair<string,int>("duration", recDuration));
+ intTokens.insert(pair<string,int>("durationevent", duration));
+
+ static cPlugin *pScraper = GetScraperPlugin();
+ if (!pScraper || !recording) {
+ intTokens.insert(pair<string,int>("hasposterthumbnail", false));
+ intTokens.insert(pair<string,int>("thumbnailbwidth", -1));
+ intTokens.insert(pair<string,int>("thumbnailheight", -1));
+ stringTokens.insert(pair<string,string>("thumbnailpath", ""));
+ return;
+ }
+
+ ScraperGetPosterThumb call;
+ call.event = NULL;
+ call.recording = recording;
+ if (pScraper->Service("GetPosterThumb", &call)) {
+ intTokens.insert(pair<string,int>("hasposterthumbnail", true));
+ intTokens.insert(pair<string,int>("thumbnailbwidth", call.poster.width));
+ intTokens.insert(pair<string,int>("thumbnailheight", call.poster.height));
+ stringTokens.insert(pair<string,string>("thumbnailpath", call.poster.path));
+ } else {
+ intTokens.insert(pair<string,int>("hasposterthumbnail", false));
+ intTokens.insert(pair<string,int>("thumbnailbwidth", -1));
+ intTokens.insert(pair<string,int>("thumbnailheight", -1));
+ stringTokens.insert(pair<string,string>("thumbnailpath", ""));
+ }
+}
+
+
+void cDisplayMenuItemRecordingView::Prepare(void) {
+ ArrangeContainer();
+}
+
+void cDisplayMenuItemRecordingView::Render(void) {
+
+ DrawListItem(&stringTokens, &intTokens);
+
+ if (current) {
+ cTemplateViewElement *tmplCurrent = tmplList->GetListElementCurrent();
+ if (tmplCurrent) {
+ currentView = new cDisplayMenuItemCurrentRecordingView(tmplCurrent, recording, level, total, newRecs);
+ currentView->Start();
+ }
+ }
+
+ dirty = false;
+}
+
+void cDisplayMenuItemRecordingView::Debug(void) {
+ esyslog("skindesigner: Recording Menu Item ---------------");
+ cDisplayMenuItemView::Debug();
+ esyslog("skindesigner: Recording: %s", recording ? recording->Title() : "Recording is NULL");
+}
+
+/*************************************************************
+* cDisplayMenuItemTrackView
+*************************************************************/
+
+cDisplayMenuItemTrackView::cDisplayMenuItemTrackView(cTemplateViewList *tmplList, const char *title, bool current, bool selectable, int numTracks)
+ : cDisplayMenuItemView(tmplList, current, selectable) {
+ this->title = title;
+ this->numTracks = numTracks;
+}
+
+cDisplayMenuItemTrackView::~cDisplayMenuItemTrackView() {
+}
+
+void cDisplayMenuItemTrackView::SetTokens(void) {
+ if (!itemInit) return;
+ itemInit = false;
+ if (!title) return;
+
+ stringTokens.insert(pair<string,string>("title", title));
+}
+
+
+void cDisplayMenuItemTrackView::Prepare(void) {
+ ArrangeContainer();
+}
+
+void cDisplayMenuItemTrackView::Render(void) {
+
+ DrawListItem(&stringTokens, &intTokens);
+
+ dirty = false;
+}
+
+void cDisplayMenuItemTrackView::Debug(void) {
+ esyslog("skindesigner: Tracks Menu Item ---------------");
+ cDisplayMenuItemView::Debug();
+ esyslog("skindesigner: Title: %s", title);
+}
+
diff --git a/views/displaymenuitemview.h b/views/displaymenuitemview.h
new file mode 100644
index 0000000..724fed5
--- /dev/null
+++ b/views/displaymenuitemview.h
@@ -0,0 +1,141 @@
+#ifndef __DISPLAYMENUITEMVIEW_H
+#define __DISPLAYMENUITEMVIEW_H
+
+#include "../libtemplate/template.h"
+#include "view.h"
+#include "displaymenuitemcurrentview.h"
+
+class cDisplayMenuItemView : public cViewListItem {
+private:
+protected:
+ bool itemInit;
+ bool dirty;
+ bool current;
+ bool selectable;
+ int num;
+ cTemplateViewList *tmplList;
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+ cDisplayMenuItemCurrentView *currentView;
+ virtual void Action(void);
+public:
+ cDisplayMenuItemView(cTemplateViewList *tmplList, bool current, bool selectable);
+ virtual ~cDisplayMenuItemView();
+ void SetCurrent(bool cur);
+ void SetNumber(int n) { num = n; };
+ void ArrangeContainer(void);
+ bool Current(void) { return current; };
+ void PrepareScrolling(void);
+ void EndScrolling(void);
+ virtual void SetTokens(void) {};
+ virtual void Prepare(void) {};
+ virtual void Render(void) {};
+ virtual void Clear(void);
+ bool Dirty(void) { return dirty; };
+ void Stop(void);
+ virtual void Debug(void);
+};
+
+class cDisplayMenuItemDefaultView: public cDisplayMenuItemView {
+private:
+ int *tabs;
+ int *tabWidths;
+ string *tabTexts;
+ int maxTabs;
+public:
+ cDisplayMenuItemDefaultView(cTemplateViewList *tmplList, string *tabTexts, int *tabs, int *tabWidths, bool current, bool selectable);
+ virtual ~cDisplayMenuItemDefaultView();
+ void SetTabTexts(string *tabTexts);
+ void SetTokens(void);
+ void Prepare(void);
+ void Render(void);
+ void Debug(void);
+};
+
+class cDisplayMenuItemMainView: public cDisplayMenuItemView {
+private:
+ string text;
+ string number;
+ string label;
+ string icon;
+ void SplitMenuText(void);
+public:
+ cDisplayMenuItemMainView(cTemplateViewList *tmplList, string itemText, bool current, bool selectable);
+ virtual ~cDisplayMenuItemMainView();
+ void SetTokens(void);
+ void Prepare(void);
+ void Render(void);
+ void Debug(void);
+};
+
+class cDisplayMenuItemSchedulesView: public cDisplayMenuItemView {
+private:
+ const cEvent *event;
+ const cChannel *channel;
+ eTimerMatch timerMatch;
+ eMenuCategory cat;
+ string ParseSeparator(string sep);
+public:
+ cDisplayMenuItemSchedulesView(cTemplateViewList *tmplList, const cEvent *event, const cChannel *channel, eTimerMatch timerMatch,
+ eMenuCategory cat, bool current, bool selectable);
+ virtual ~cDisplayMenuItemSchedulesView();
+ void SetTokens(void);
+ void Prepare(void);
+ void Render(void);
+ void Debug(void);
+};
+
+class cDisplayMenuItemChannelsView: public cDisplayMenuItemView {
+private:
+ const cChannel *channel;
+ bool withProvider;
+public:
+ cDisplayMenuItemChannelsView(cTemplateViewList *tmplList, const cChannel *channel, bool withProvider, bool current, bool selectable);
+ virtual ~cDisplayMenuItemChannelsView();
+ void SetTokens(void);
+ void Prepare(void);
+ void Render(void);
+ void Debug(void);
+};
+
+class cDisplayMenuItemTimersView: public cDisplayMenuItemView {
+private:
+ const cTimer *timer;
+public:
+ cDisplayMenuItemTimersView(cTemplateViewList *tmplList, const cTimer *timer, bool current, bool selectable);
+ virtual ~cDisplayMenuItemTimersView();
+ void SetTokens(void);
+ void Prepare(void);
+ void Render(void);
+ void Debug(void);
+};
+
+class cDisplayMenuItemRecordingView: public cDisplayMenuItemView {
+private:
+ const cRecording *recording;
+ int level;
+ int total;
+ int newRecs;
+public:
+ cDisplayMenuItemRecordingView(cTemplateViewList *tmplList, const cRecording *recording, int level, int total, int newRecs, bool current, bool selectable);
+ virtual ~cDisplayMenuItemRecordingView();
+ void SetTokens(void);
+ void Prepare(void);
+ void Render(void);
+ void Debug(void);
+};
+
+class cDisplayMenuItemTrackView: public cDisplayMenuItemView {
+private:
+ const char *title;
+ int numTracks;
+public:
+ cDisplayMenuItemTrackView(cTemplateViewList *tmplList, const char *title, bool current, bool selectable, int numTracks);
+ virtual ~cDisplayMenuItemTrackView();
+ void SetTokens(void);
+ void Prepare(void);
+ void Render(void);
+ void Debug(void);
+};
+
+#endif //__DISPLAYMENUITEMVIEW_H
diff --git a/views/displaymenulistview.c b/views/displaymenulistview.c
new file mode 100644
index 0000000..eb8581e
--- /dev/null
+++ b/views/displaymenulistview.c
@@ -0,0 +1,216 @@
+#include <vdr/menu.h>
+#include "displaymenulistview.h"
+
+
+cDisplayMenuListView::cDisplayMenuListView(cTemplateViewList *tmplList, int count) {
+ oneColumn = true;
+ this->tmplList = tmplList;
+ if (count < 0) {
+ //if count is not set, the fixed number of items is configured in the template
+ itemCount = tmplList->GetNumericParameter(ptNumElements);
+ } else {
+ //else use the actual numbers of elements
+ itemCount = count;
+ map < string, int > intTokens;
+ intTokens.insert(pair<string,int>("numelements", count));
+ tmplList->CalculateListParameters(&intTokens);
+ }
+ menuItems = new cDisplayMenuItemView*[itemCount];
+ for (int i=0; i<itemCount; i++)
+ menuItems[i] = NULL;
+ tabs = new int[cSkinDisplayMenu::MaxTabs];
+ for (int i=0; i<cSkinDisplayMenu::MaxTabs; i++)
+ tabs[i] = 0;
+ tabWidths = new int[cSkinDisplayMenu::MaxTabs];
+ for (int i=0; i<cSkinDisplayMenu::MaxTabs; i++)
+ tabWidths[i] = 0;
+}
+
+cDisplayMenuListView::~cDisplayMenuListView() {
+ Clear();
+ delete[] menuItems;
+ delete[] tabs;
+ delete[] tabWidths;
+}
+
+void cDisplayMenuListView::SetTabs(int tab1, int tab2, int tab3, int tab4, int tab5) {
+
+ int menuItemWidth = 1920;
+ int averageFontWidth = 20;
+ if (tmplList) {
+ menuItemWidth = tmplList->GetMenuItemWidth();
+ averageFontWidth = tmplList->GetAverageFontWidth();
+ }
+
+ if (!tab1) {
+ tabs[0] = 0;
+ tabWidths[0] = menuItemWidth;
+ } else {
+ tabs[0] = 0;
+ if (!tab2) {
+ tabs[1] = menuItemWidth/2;
+ tabWidths[0] = tabs[1];
+ tabWidths[1] = tabs[1];
+ } else {
+ tabs[0] = 0;
+ tabs[1] = tab1 ? tabs[0] + tab1 : 0;
+ tabs[2] = tab2 ? tabs[1] + tab2 : 0;
+ tabs[3] = tab3 ? tabs[2] + tab3 : 0;
+ tabs[4] = tab4 ? tabs[3] + tab4 : 0;
+ tabs[5] = tab5 ? tabs[4] + tab5 : 0;
+ for (int i = 1; i < cSkinDisplayMenu::MaxTabs; i++)
+ tabs[i] *= averageFontWidth;
+
+ for (int i = 0; i < cSkinDisplayMenu::MaxTabs; i++) {
+ if (i == cSkinDisplayMenu::MaxTabs - 1) {
+ tabWidths[i] = menuItemWidth - tabs[i];
+ } else {
+ tabWidths[i] = tabs[i+1] - tabs[i];
+ }
+ }
+ }
+ }
+}
+
+int cDisplayMenuListView::GetListWidth(void) {
+ if (tmplList) {
+ return tmplList->GetMenuItemWidth();
+ }
+ return 1920;
+}
+
+
+void cDisplayMenuListView::Clear(void) {
+ for (int i=0; i<itemCount; i++) {
+ if (menuItems[i]) {
+ delete menuItems[i];
+ menuItems[i] = NULL;
+ }
+ }
+ oneColumn = true;
+ for (int i=0; i<cSkinDisplayMenu::MaxTabs; i++) {
+ tabs[i] = 0;
+ tabWidths[i] = 0;
+ }
+}
+
+void cDisplayMenuListView::AddDefaultMenuItem(int index, string *tabTexts, bool current, bool selectable) {
+ if (menuItems[index]) {
+ cDisplayMenuItemDefaultView *menuItem = dynamic_cast<cDisplayMenuItemDefaultView*>(menuItems[index]);
+ if (!menuItem)
+ return;
+ menuItem->SetCurrent(current);
+ menuItem->SetTabTexts(tabTexts);
+ return;
+ }
+ for (int i=1; i<cSkinDisplayMenu::MaxTabs; i++) {
+ if (tabTexts[i].size() > 0) {
+ oneColumn = false;
+ break;
+ }
+ }
+ cDisplayMenuItemView *item = new cDisplayMenuItemDefaultView(tmplList, tabTexts, tabs, tabWidths, current, selectable);
+ menuItems[index] = item;
+}
+
+void cDisplayMenuListView::AddMainMenuItem(int index, const char *itemText, bool current, bool selectable) {
+ if (menuItems[index]) {
+ menuItems[index]->SetCurrent(current);
+ return;
+ }
+ cDisplayMenuItemView *item = new cDisplayMenuItemMainView(tmplList, itemText, current, selectable);
+ menuItems[index] = item;
+}
+
+void cDisplayMenuListView::AddSetupMenuItem(int index, const char *itemText, bool current, bool selectable) {
+ if (menuItems[index]) {
+ menuItems[index]->SetCurrent(current);
+ return;
+ }
+ cDisplayMenuItemView *item = new cDisplayMenuItemMainView(tmplList, itemText, current, selectable);
+ menuItems[index] = item;
+}
+
+void cDisplayMenuListView::AddSchedulesMenuItem(int index, const cEvent *event, const cChannel *channel, eTimerMatch timerMatch,
+ eMenuCategory cat, bool current, bool selectable) {
+ if (menuItems[index]) {
+ menuItems[index]->SetCurrent(current);
+ return;
+ }
+ cDisplayMenuItemView *item = new cDisplayMenuItemSchedulesView(tmplList, event, channel, timerMatch, cat, current, selectable);
+ menuItems[index] = item;
+}
+
+void cDisplayMenuListView::AddChannelsMenuItem(int index, const cChannel *channel, bool withProvider, bool current, bool selectable) {
+ if (menuItems[index]) {
+ menuItems[index]->SetCurrent(current);
+ return;
+ }
+ cDisplayMenuItemView *item = new cDisplayMenuItemChannelsView(tmplList, channel, withProvider, current, selectable);
+ menuItems[index] = item;
+}
+
+void cDisplayMenuListView::AddTimersMenuItem(int index, const cTimer *timer, bool current, bool selectable) {
+ if (menuItems[index]) {
+ menuItems[index]->SetCurrent(current);
+ return;
+ }
+ cDisplayMenuItemView *item = new cDisplayMenuItemTimersView(tmplList, timer, current, selectable);
+ menuItems[index] = item;
+}
+
+void cDisplayMenuListView::AddRecordingMenuItem(int index, const cRecording *recording, int level, int total, int isNew, bool current, bool selectable) {
+ if (menuItems[index]) {
+ menuItems[index]->SetCurrent(current);
+ return;
+ }
+ cDisplayMenuItemView *item = new cDisplayMenuItemRecordingView(tmplList, recording, level, total, isNew, current, selectable);
+ menuItems[index] = item;
+}
+
+void cDisplayMenuListView::AddTracksMenuItem(int index, const char *title, bool current, bool selectable) {
+ if (menuItems[index]) {
+ menuItems[index]->SetCurrent(current);
+ return;
+ }
+ cDisplayMenuItemView *item = new cDisplayMenuItemTrackView(tmplList, title, current, selectable, itemCount);
+ menuItems[index] = item;
+}
+
+void cDisplayMenuListView::Render(void) {
+ if (tabs[1] && oneColumn) {
+ tabs[0] = 0;
+ tabWidths[0] = tmplList->GetMenuItemWidth();
+ for (int i=1; i<cSkinDisplayMenu::MaxTabs; i++) {
+ tabs[i] = 0;
+ tabWidths[i] = 0;
+ }
+ }
+ int current = -1;
+ for (int i=0; i<itemCount; i++) {
+ if (menuItems[i] && menuItems[i]->Dirty()) {
+ menuItems[i]->Clear();
+ menuItems[i]->SetNumber(i);
+ menuItems[i]->Prepare();
+ menuItems[i]->SetTokens();
+ menuItems[i]->Render();
+ if (menuItems[i]->Current()) {
+ current = i;
+ } else {
+ menuItems[i]->Stop();
+ }
+ }
+ }
+ if (current > -1) {
+ menuItems[current]->Start();
+ }
+}
+
+void cDisplayMenuListView::Debug(void) {
+ for (int i=0; i<itemCount; i++) {
+ esyslog("skindesigner: item %d", i);
+ if (menuItems[i]) {
+ menuItems[i]->Debug();
+ }
+ }
+}
diff --git a/views/displaymenulistview.h b/views/displaymenulistview.h
new file mode 100644
index 0000000..1c2c85f
--- /dev/null
+++ b/views/displaymenulistview.h
@@ -0,0 +1,35 @@
+#ifndef __DISPLAYMENULISTVIEW_H
+#define __DISPLAYMENULISTVIEW_H
+
+#include "../libtemplate/template.h"
+#include "view.h"
+#include "displaymenuitemview.h"
+
+class cDisplayMenuListView {
+private:
+ cTemplateViewList *tmplList;
+ int itemCount;
+ cDisplayMenuItemView **menuItems;
+ int *tabs;
+ int *tabWidths;
+ bool oneColumn;
+public:
+ cDisplayMenuListView(cTemplateViewList *tmplList, int count = -1);
+ virtual ~cDisplayMenuListView();
+ void Clear(void);
+ void SetTabs(int tab1, int tab2, int tab3, int tab4, int tab5);
+ int GetMaxItems(void) { return itemCount; };
+ int GetListWidth(void);
+ void AddDefaultMenuItem(int index, string *tabTexts, bool current, bool selectable);
+ void AddMainMenuItem(int index, const char *itemText, bool current, bool selectable);
+ void AddSetupMenuItem(int index, const char *itemText, bool current, bool selectable);
+ void AddSchedulesMenuItem(int index, const cEvent *event, const cChannel *channel, eTimerMatch timerMatch, eMenuCategory cat, bool current, bool selectable);
+ void AddChannelsMenuItem(int index, const cChannel *channel, bool withProvider, bool current, bool selectable);
+ void AddTimersMenuItem(int index, const cTimer *timer, bool current, bool selectable);
+ void AddRecordingMenuItem(int index, const cRecording *recording, int level, int total, int isNew, bool current, bool selectable);
+ void AddTracksMenuItem(int index, const char *title, bool current, bool selectable);
+ void Render(void);
+ void Debug(void);
+};
+
+#endif //__DISPLAYMENULISTVIEW_H
diff --git a/views/displaymenurootview.c b/views/displaymenurootview.c
new file mode 100644
index 0000000..9ee1bcf
--- /dev/null
+++ b/views/displaymenurootview.c
@@ -0,0 +1,495 @@
+#define __STL_CONFIG_H
+#include <vdr/menu.h>
+#include "displaymenurootview.h"
+#include "../config.h"
+#include "../libcore/helpers.h"
+
+cDisplayMenuRootView::cDisplayMenuRootView(cTemplateView *rootView) : cView(rootView) {
+ viewType = svUndefined;
+ subView = NULL;
+ subViewAvailable = false;
+ view = NULL;
+ listView = NULL;
+ detailView = NULL;
+ defaultBackgroundDrawn = false;
+ defaultHeaderDrawn = false;
+ defaultButtonsDrawn = false;
+ defaultDateTimeDrawn = false;
+ defaultMessageDrawn = false;
+ DeleteOsdOnExit();
+ SetFadeTime(tmplView->GetNumericParameter(ptFadeTime));
+}
+
+cDisplayMenuRootView::~cDisplayMenuRootView() {
+ if (view)
+ delete view;
+ if (listView)
+ delete listView;
+ if (detailView)
+ delete detailView;
+}
+
+/*******************************************************************
+* Public Functions
+*******************************************************************/
+
+bool cDisplayMenuRootView::createOsd(void) {
+ cRect osdSize = tmplView->GetOsdSize();
+ bool ok = CreateOsd(cOsd::OsdLeft() + osdSize.X(),
+ cOsd::OsdTop() + osdSize.Y(),
+ osdSize.Width(),
+ osdSize.Height());
+ return ok;
+}
+
+/* Categories:
+mcUndefined = -1,
+mcUnknown = 0,
+1 mcMain,
+2 mcSchedule,
+3 mcScheduleNow,
+4 mcScheduleNext,
+5 mcChannel,
+6 mcChannelEdit,
+7 mcTimer,
+8 mcTimerEdit,
+9 mcRecording,
+10 mcRecordingInfo,
+11 mcPlugin,
+12 mcPluginSetup,
+13 mcSetup,
+14 mcSetupOsd,
+15 mcSetupEpg,
+16 mcSetupDvb,
+17 mcSetupLnb,
+18 mcSetupCam,
+19 mcSetupRecord,
+20 mcSetupReplay,
+21 mcSetupMisc,
+22 mcSetupPlugins,
+23 mcCommand,
+24 mcEvent,
+25 mcText,
+26 mcFolder,
+27 mcCam
+*/
+
+void cDisplayMenuRootView::SetMenu(eMenuCategory menuCat, bool menuInit) {
+ eSubView newViewType = svUndefined;
+ bool isListView = true;
+ switch (menuCat) {
+ case mcMain:
+ newViewType = svMenuMain;
+ break;
+ case mcSetup:
+ newViewType = svMenuSetup;
+ break;
+ case mcSchedule:
+ case mcScheduleNow:
+ case mcScheduleNext:
+ newViewType = svMenuSchedules;
+ if (view)
+ view->SetMenuCat(menuCat);
+ break;
+ case mcChannel:
+ newViewType = svMenuChannels;
+ break;
+ case mcTimer:
+ newViewType = svMenuTimers;
+ break;
+ case mcRecording:
+ newViewType = svMenuRecordings;
+ break;
+ case mcEvent:
+ newViewType = svMenuDetailedEpg;
+ isListView = false;
+ break;
+ case mcRecordingInfo:
+ newViewType = svMenuDetailedRecording;
+ isListView = false;
+ break;
+ case mcText:
+ newViewType = svMenuDetailedText;
+ isListView = false;
+ break;
+ default:
+ newViewType = svMenuDefault;
+ break;
+ }
+ if (newViewType != viewType) {
+ subView = tmplView->GetSubView(newViewType);
+ if (!subView) {
+ subViewAvailable = false;
+ subView = tmplView->GetSubView(svMenuDefault);
+ } else {
+ subViewAvailable = true;
+ }
+ //Cleanup
+ if (view) {
+ delete view;
+ view = NULL;
+ }
+ if (listView) {
+ delete listView;
+ listView = NULL;
+ }
+ if (detailView) {
+ delete detailView;
+ detailView = NULL;
+ }
+
+ //Create new View
+ switch (newViewType) {
+ case svMenuMain:
+ view = new cDisplayMenuMainView(subView, menuInit);
+ break;
+ case svMenuSchedules:
+ if (subViewAvailable)
+ view = new cDisplayMenuSchedulesView(subView, menuCat, menuInit);
+ else
+ view = new cDisplayMenuView(subView, menuInit);
+ break;
+ default:
+ view = new cDisplayMenuView(subView, menuInit);
+ }
+
+ //Cleanup root view
+ ClearRootView();
+
+ if (isListView) {
+ //Create menu item list
+ cTemplateViewList *tmplMenuItems = subView->GetViewList(vlMenuItem);
+ if (!tmplMenuItems)
+ return;
+ listView = new cDisplayMenuListView(tmplMenuItems);
+ } else {
+ //Create detailed view
+ detailView = new cDisplayMenuDetailView(subView);
+ }
+ viewType = newViewType;
+ }
+}
+
+void cDisplayMenuRootView::SetTitle(const char *title) {
+ menuTitle = title;
+ if (view)
+ view->SetTitle(title);
+}
+
+void cDisplayMenuRootView::SetButtonTexts(const char *Red, const char *Green, const char *Yellow, const char *Blue) {
+ if (Red)
+ buttonTexts[0] = Red;
+ else
+ buttonTexts[0] = "";
+ if (Green)
+ buttonTexts[1] = Green;
+ else
+ buttonTexts[1] = "";
+ if (Yellow)
+ buttonTexts[2] = Yellow;
+ else
+ buttonTexts[2] = "";
+ if (Blue)
+ buttonTexts[3] = Blue;
+ else
+ buttonTexts[3] = "";
+ if (view)
+ view->SetButtonTexts(buttonTexts);
+}
+
+void cDisplayMenuRootView::SetTabs(int tab1, int tab2, int tab3, int tab4, int tab5) {
+ if (listView) {
+ listView->SetTabs(tab1, tab2, tab3, tab4, tab5);
+ }
+}
+
+void cDisplayMenuRootView::SetMessage(eMessageType type, const char *text) {
+ if (!view)
+ return;
+ if (!view->DrawMessage(type, text)) {
+ defaultMessageDrawn = true;
+ DrawMessage(type, text);
+ } else {
+ defaultMessageDrawn = false;
+ }
+}
+
+void cDisplayMenuRootView::SetDetailedViewEvent(const cEvent *event) {
+ if (!detailView)
+ detailView = new cDisplayMenuDetailView(subView);
+ detailView->SetEvent(event);
+}
+
+void cDisplayMenuRootView::SetDetailedViewRecording(const cRecording *recording) {
+ if (!detailView)
+ detailView = new cDisplayMenuDetailView(subView);
+ detailView->SetRecording(recording);
+}
+
+void cDisplayMenuRootView::SetDetailedViewText(const char *text) {
+ if (!detailView)
+ detailView = new cDisplayMenuDetailView(subView);
+ detailView->SetText(text);
+}
+
+void cDisplayMenuRootView::KeyInput(bool up, bool page) {
+ if (!detailView)
+ return;
+
+ if (up && page) {
+ detailView->KeyLeft();
+ } else if (!up && page) {
+ detailView->KeyRight();
+ } else if (up && !page) {
+ detailView->KeyUp();
+ } else if (!up && !page) {
+ detailView->KeyDown();
+ }
+}
+
+void cDisplayMenuRootView::Clear(void) {
+ if (listView) {
+ listView->Clear();
+ }
+ if (detailView) {
+ delete detailView;
+ detailView = NULL;
+ }
+}
+
+void cDisplayMenuRootView::ClearRootView(void) {
+ if (defaultBackgroundDrawn && view->BackgroundImplemented())
+ ClearViewElement(veBackground);
+ if (defaultHeaderDrawn)
+ ClearViewElement(veHeader);
+ if (defaultButtonsDrawn)
+ ClearViewElement(veButtons);
+ if (defaultDateTimeDrawn)
+ ClearViewElement(veDateTime);
+ if (defaultMessageDrawn)
+ ClearViewElement(veMessage);
+}
+
+int cDisplayMenuRootView::GetMaxItems(void) {
+ if (listView) {
+ return listView->GetMaxItems();
+ }
+ return 0;
+}
+
+int cDisplayMenuRootView::GetListViewWidth(void) {
+ if (listView) {
+ return listView->GetListWidth();
+ }
+ return 0;
+}
+
+int cDisplayMenuRootView::GetTextAreaWidth(void) {
+ if (!tmplView)
+ return 1900;
+ cTemplateView *tempSubView = tmplView->GetSubView(svMenuDefault);
+ if (!tempSubView)
+ return 1900;
+ int areaWidth = tempSubView->GetNumericParameter(ptWidth);
+ if (areaWidth > 0)
+ return areaWidth;
+ return 1900;
+}
+
+
+void cDisplayMenuRootView::Render(void) {
+
+ if (!view->DrawBackground()) {
+ if (!defaultBackgroundDrawn) {
+ defaultBackgroundDrawn = true;
+ DrawBackground();
+ }
+ } else {
+ defaultBackgroundDrawn = false;
+ }
+
+ if (!view->DrawHeader()) {
+ defaultHeaderDrawn = true;
+ DrawHeader();
+ } else {
+ defaultHeaderDrawn = false;
+ }
+
+ if (!view->DrawColorButtons()) {
+ defaultButtonsDrawn = true;
+ DrawColorButtons();
+ } else {
+ defaultButtonsDrawn = false;
+ }
+
+ if (!view->DrawDateTime()) {
+ defaultDateTimeDrawn = true;
+ DrawDateTime();
+ } else {
+ defaultDateTimeDrawn = false;
+ }
+
+ view->DrawStaticViewElements();
+ view->DrawDynamicViewElements();
+}
+
+void cDisplayMenuRootView::RenderMenuItems(void) {
+ if (listView)
+ listView->Render();
+}
+
+void cDisplayMenuRootView::RenderDetailView(void) {
+ if (detailView)
+ detailView->Render();
+}
+
+void cDisplayMenuRootView::RenderMenuScrollBar(int Total, int Offset) {
+ if (!listView)
+ return;
+ view->DrawScrollbar(listView->GetMaxItems(), Total, Offset);
+}
+
+bool cDisplayMenuRootView::RenderDynamicElements(void) {
+ return view->DrawDynamicViewElements();
+}
+
+/*******************************************************************
+* Private Functions
+*******************************************************************/
+
+void cDisplayMenuRootView::DrawBackground(void) {
+ DrawViewElement(veBackground);
+}
+void cDisplayMenuRootView::DrawHeader(void) {
+ if (!ViewElementImplemented(veHeader)) {
+ return;
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ stringTokens.insert(pair<string,string>("title", menuTitle));
+ stringTokens.insert(pair<string,string>("vdrversion", VDRVERSION));
+
+ //check for standard menu entries
+ bool hasIcon = false;
+ string icon = imgCache->GetIconName(menuTitle);
+ if (icon.size() > 0)
+ hasIcon = true;
+
+ stringTokens.insert(pair<string,string>("icon", icon));
+ intTokens.insert(pair<string,int>("hasicon", hasIcon));
+
+ ClearViewElement(veHeader);
+ DrawViewElement(veHeader, &stringTokens, &intTokens);
+}
+
+void cDisplayMenuRootView::DrawDateTime(void) {
+ if (!ViewElementImplemented(veDateTime)) {
+ return;
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ time_t t = time(0); // get time now
+ struct tm * now = localtime(&t);
+
+ intTokens.insert(pair<string, int>("year", now->tm_year + 1900));
+ intTokens.insert(pair<string, int>("day", now->tm_mday));
+
+ char monthname[20];
+ char monthshort[10];
+ strftime(monthshort, sizeof(monthshort), "%b", now);
+ strftime(monthname, sizeof(monthname), "%B", now);
+
+ stringTokens.insert(pair<string,string>("monthname", monthname));
+ stringTokens.insert(pair<string,string>("monthnameshort", monthshort));
+ stringTokens.insert(pair<string,string>("month", *cString::sprintf("%02d", now->tm_mon + 1)));
+ stringTokens.insert(pair<string,string>("dayleadingzero", *cString::sprintf("%02d", now->tm_mday)));
+ stringTokens.insert(pair<string,string>("dayname", *WeekDayNameFull(now->tm_wday)));
+ stringTokens.insert(pair<string,string>("daynameshort", *WeekDayName(now->tm_wday)));
+ stringTokens.insert(pair<string,string>("time", *TimeString(t)));
+
+ ClearViewElement(veDateTime);
+ DrawViewElement(veDateTime, &stringTokens, &intTokens);
+
+}
+
+
+void cDisplayMenuRootView::DrawColorButtons(void) {
+ if (!ViewElementImplemented(veButtons)) {
+ return;
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ stringTokens.insert(pair<string,string>("red", buttonTexts[0]));
+ stringTokens.insert(pair<string,string>("green", buttonTexts[1]));
+ stringTokens.insert(pair<string,string>("yellow", buttonTexts[2]));
+ stringTokens.insert(pair<string,string>("blue", buttonTexts[3]));
+
+ int colorKeys[4] = { Setup.ColorKey0, Setup.ColorKey1, Setup.ColorKey2, Setup.ColorKey3 };
+
+ for (int button = 1; button < 5; button++) {
+ string red = *cString::sprintf("red%d", button);
+ string green = *cString::sprintf("green%d", button);
+ string yellow = *cString::sprintf("yellow%d", button);
+ string blue = *cString::sprintf("blue%d", button);
+ bool isRed = false;
+ bool isGreen = false;
+ bool isYellow = false;
+ bool isBlue = false;
+ switch (colorKeys[button-1]) {
+ case 0:
+ isRed = true;
+ break;
+ case 1:
+ isGreen = true;
+ break;
+ case 2:
+ isYellow = true;
+ break;
+ case 3:
+ isBlue = true;
+ break;
+ default:
+ break;
+ }
+ intTokens.insert(pair<string, int>(red, isRed));
+ intTokens.insert(pair<string, int>(green, isGreen));
+ intTokens.insert(pair<string, int>(yellow, isYellow));
+ intTokens.insert(pair<string, int>(blue, isBlue));
+ }
+
+ ClearViewElement(veButtons);
+ DrawViewElement(veButtons, &stringTokens, &intTokens);
+}
+
+void cDisplayMenuRootView::DrawMessage(eMessageType type, const char *text) {
+ if (!text) {
+ ClearViewElement(veMessage);
+ return;
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ intTokens.insert(pair<string, int>("status", (type == mtStatus) ? true : false));
+ intTokens.insert(pair<string, int>("info", (type == mtInfo) ? true : false));
+ intTokens.insert(pair<string, int>("warning", (type == mtWarning) ? true : false));
+ intTokens.insert(pair<string, int>("error", (type == mtError) ? true : false));
+ stringTokens.insert(pair<string,string>("text", text));
+
+ ClearViewElement(veMessage);
+ DrawViewElement(veMessage, &stringTokens, &intTokens);
+}
+
+void cDisplayMenuRootView::Action(void) {
+ SetInitFinished();
+ Render();
+ view->Start();
+ FadeIn();
+ DoFlush();
+}
diff --git a/views/displaymenurootview.h b/views/displaymenurootview.h
new file mode 100644
index 0000000..b3f4c62
--- /dev/null
+++ b/views/displaymenurootview.h
@@ -0,0 +1,57 @@
+#ifndef __DISPLAYMENUROOTVIEW_H
+#define __DISPLAYMENUROOTVIEW_H
+
+#include "../libtemplate/template.h"
+#include "displaymenuview.h"
+#include "displaymenulistview.h"
+#include "displaymenudetailview.h"
+
+class cDisplayMenuRootView : public cView {
+private:
+ eSubView viewType;
+ cTemplateView *subView;
+ bool subViewAvailable;
+ cDisplayMenuView *view;
+ cDisplayMenuListView *listView;
+ cDisplayMenuDetailView *detailView;
+ string menuTitle;
+ string buttonTexts[4];
+ bool defaultBackgroundDrawn;
+ bool defaultHeaderDrawn;
+ bool defaultButtonsDrawn;
+ bool defaultDateTimeDrawn;
+ bool defaultMessageDrawn;
+ void DrawBackground(void);
+ void DrawHeader(void);
+ void DrawDateTime(void);
+ void DrawColorButtons(void);
+ void DrawMessage(eMessageType type, const char *text);
+ void ClearRootView(void);
+ virtual void Action(void);
+public:
+ cDisplayMenuRootView(cTemplateView *rootView);
+ virtual ~cDisplayMenuRootView();
+ bool createOsd(void);
+ void SetMenu(eMenuCategory menuCat, bool menuInit);
+ void SetTitle(const char *title);
+ void SetChannel(const cChannel *channel) { view->SetChannel(channel); };
+ void SetButtonTexts(const char *Red, const char *Green, const char *Yellow, const char *Blue);
+ void SetTabs(int tab1, int tab2, int tab3, int tab4, int tab5);
+ void SetMessage(eMessageType type, const char *text);
+ void SetDetailedViewEvent(const cEvent *event);
+ void SetDetailedViewRecording(const cRecording *recording);
+ void SetDetailedViewText(const char *text);
+ void KeyInput(bool up, bool page);
+ void Clear(void);
+ int GetMaxItems(void);
+ int GetListViewWidth(void);
+ int GetTextAreaWidth(void);
+ bool SubViewAvailable(void) { return subViewAvailable; };
+ cDisplayMenuListView *GetListView(void) { return listView; };
+ void Render(void);
+ void RenderMenuItems(void);
+ void RenderDetailView(void);
+ void RenderMenuScrollBar(int Total, int Offset);
+ bool RenderDynamicElements(void);
+};
+#endif //__DISPLAYMENUROOTVIEW_H
diff --git a/views/displaymenutabview.c b/views/displaymenutabview.c
new file mode 100644
index 0000000..f9e03f9
--- /dev/null
+++ b/views/displaymenutabview.c
@@ -0,0 +1,126 @@
+#include "displaymenutabview.h"
+
+
+cDisplayMenuTabView::cDisplayMenuTabView(cTemplateViewTab *tmplTab) : cView(tmplTab) {
+}
+
+cDisplayMenuTabView::~cDisplayMenuTabView() {
+ CancelSave();
+}
+
+void cDisplayMenuTabView::SetTokens(map < string, int > *intTokens, map < string, string > *stringTokens, map < string, vector< map< string, string > > > *loopTokens) {
+ this->intTokens = intTokens;
+ this->stringTokens = stringTokens;
+ this->loopTokens = loopTokens;
+}
+
+void cDisplayMenuTabView::Clear(void) {
+ Fill(0, clrTransparent);
+}
+
+void cDisplayMenuTabView::CreateTab(void) {
+ //Create Pixmap
+ if (!PixmapExists(0)) {
+ cSize drawportSize;
+ scrolling = tmplTab->CalculateDrawPortSize(drawportSize, loopTokens);
+ if (scrolling) {
+ CreateScrollingPixmap(0, tmplTab, drawportSize);
+ scrollingPix = 0;
+ scrollOrientation = orVertical;
+ scrollMode = smNone;
+ } else {
+ CreateViewPixmap(0, tmplTab);
+ }
+ }
+}
+
+
+void cDisplayMenuTabView::Render(void) {
+ if (tmplTab->DoDebug()) {
+ tmplTab->Debug();
+ }
+ //Draw Tab, flushing every loop
+ DrawPixmap(0, tmplTab, loopTokens, true);
+}
+
+bool cDisplayMenuTabView::KeyUp(void) {
+ if (!scrolling)
+ return false;
+ int scrollStep = tmplTab->GetScrollStep();
+ int aktHeight = DrawportY(0);
+ if (aktHeight >= 0) {
+ return false;
+ }
+ int newY = aktHeight + scrollStep;
+ if (newY > 0)
+ newY = 0;
+ SetDrawPortPoint(0, cPoint(0, newY));
+ return true;
+}
+
+bool cDisplayMenuTabView::KeyDown(void) {
+ if (!scrolling)
+ return false;
+
+ int scrollStep = tmplTab->GetScrollStep();
+ int aktHeight = DrawportY(0);
+ int totalHeight = DrawportHeight(0);
+ int screenHeight = Height(0);
+
+ if (totalHeight - ((-1)*aktHeight) == screenHeight) {
+ return false;
+ }
+ int newY = aktHeight - scrollStep;
+ if ((-1)*newY > totalHeight - screenHeight)
+ newY = (-1)*(totalHeight - screenHeight);
+ SetDrawPortPoint(0, cPoint(0, newY));
+ return true;
+}
+
+bool cDisplayMenuTabView::KeyLeft(void) {
+ if (!scrolling)
+ return false;
+ if (!PixmapExists(0))
+ return false;
+ int aktHeight = DrawportY(0);
+ int screenHeight = Height(0);
+ int newY = aktHeight + screenHeight;
+ if (newY > 0)
+ newY = 0;
+ SetDrawPortPoint(0, cPoint(0, newY));
+ return true;
+}
+
+bool cDisplayMenuTabView::KeyRight(void) {
+ if (!scrolling)
+ return false;
+ if (!PixmapExists(0))
+ return false;
+ int aktHeight = DrawportY(0);
+ int screenHeight = Height(0);
+ int totalHeight = DrawportHeight(0);
+ int newY = aktHeight - screenHeight;
+ if ((-1)*newY > totalHeight - screenHeight)
+ newY = (-1)*(totalHeight - screenHeight);
+ SetDrawPortPoint(0, cPoint(0, newY));
+ return true;
+}
+
+void cDisplayMenuTabView::GetScrollbarPosition(int &barTop, int &barHeight) {
+ int y = (-1)*DrawportY(0);
+ int totalHeight = DrawportHeight(0);
+ int screenHeight = Height(0);
+ if (totalHeight == 0)
+ return;
+ if (totalHeight <= screenHeight)
+ barHeight = 1000;
+ else {
+ barHeight = (double)screenHeight / (double) totalHeight * 1000;
+ }
+ barTop = (double)y / (double) totalHeight * 1000;
+}
+
+void cDisplayMenuTabView::Action(void) {
+ Render();
+ DoFlush();
+} \ No newline at end of file
diff --git a/views/displaymenutabview.h b/views/displaymenutabview.h
new file mode 100644
index 0000000..70a7447
--- /dev/null
+++ b/views/displaymenutabview.h
@@ -0,0 +1,27 @@
+#ifndef __DISPLAYMENUTABVIEW_H
+#define __DISPLAYMENUTABVIEW_H
+
+#include "../libtemplate/template.h"
+#include "view.h"
+
+class cDisplayMenuTabView : public cView {
+private:
+ map < string, string > *stringTokens;
+ map < string, int > *intTokens;
+ map < string, vector< map< string, string > > > *loopTokens;
+ void Action(void);
+public:
+ cDisplayMenuTabView(cTemplateViewTab *tmplTab);
+ virtual ~cDisplayMenuTabView();
+ void SetTokens(map < string, int > *intTokens, map < string, string > *stringTokens, map < string, vector< map< string, string > > > *loopTokens);
+ void Clear(void);
+ void CreateTab(void);
+ void Render(void);
+ bool KeyUp(void);
+ bool KeyDown(void);
+ bool KeyLeft(void);
+ bool KeyRight(void);
+ void GetScrollbarPosition(int &barTop, int &barHeight);
+};
+
+#endif //__DISPLAYMENUTABVIEW_H
diff --git a/views/displaymenuview.c b/views/displaymenuview.c
new file mode 100644
index 0000000..3b8c657
--- /dev/null
+++ b/views/displaymenuview.c
@@ -0,0 +1,539 @@
+#define __STL_CONFIG_H
+#include <vdr/menu.h>
+#include <vdr/videodir.h>
+#include "displaymenuview.h"
+#include "../config.h"
+#include "../libcore/helpers.h"
+#include "../libcore/timers.h"
+
+cDisplayMenuView::cDisplayMenuView(cTemplateView *tmplView, bool menuInit) : cView(tmplView) {
+ if (menuInit)
+ SetFadeTime(tmplView->GetNumericParameter(ptFadeTime));
+ else
+ SetFadeTime(0);
+ cat = mcUndefined;
+}
+
+cDisplayMenuView::~cDisplayMenuView() {
+ CancelSave();
+ FadeOut();
+}
+
+bool cDisplayMenuView::DrawBackground(void) {
+ if (!ViewElementImplemented(veBackground)) {
+ return false;
+ }
+ DrawViewElement(veBackground);
+ return true;
+}
+
+bool cDisplayMenuView::DrawHeader(void) {
+ if (!ViewElementImplemented(veHeader)) {
+ return false;
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ stringTokens.insert(pair<string,string>("title", menuTitle));
+ stringTokens.insert(pair<string,string>("vdrversion", VDRVERSION));
+
+ //check for standard menu entries
+ bool hasIcon = false;
+ string icon = imgCache->GetIconName(menuTitle);
+ if (icon.size() > 0)
+ hasIcon = true;
+ stringTokens.insert(pair<string,string>("icon", icon));
+ intTokens.insert(pair<string,int>("hasicon", hasIcon));
+
+ ClearViewElement(veHeader);
+ DrawViewElement(veHeader, &stringTokens, &intTokens);
+ return true;
+}
+
+bool cDisplayMenuView::DrawDateTime(void) {
+ if (!ViewElementImplemented(veDateTime)) {
+ return false;
+ }
+
+ cString curDate = DayDateTime();
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ time_t t = time(0); // get time now
+ struct tm * now = localtime(&t);
+
+ intTokens.insert(pair<string, int>("year", now->tm_year + 1900));
+ intTokens.insert(pair<string, int>("day", now->tm_mday));
+
+ char monthname[20];
+ char monthshort[10];
+ strftime(monthshort, sizeof(monthshort), "%b", now);
+ strftime(monthname, sizeof(monthname), "%B", now);
+
+ stringTokens.insert(pair<string,string>("monthname", monthname));
+ stringTokens.insert(pair<string,string>("monthnameshort", monthshort));
+ stringTokens.insert(pair<string,string>("month", *cString::sprintf("%02d", now->tm_mon + 1)));
+ stringTokens.insert(pair<string,string>("dayleadingzero", *cString::sprintf("%02d", now->tm_mday)));
+ stringTokens.insert(pair<string,string>("dayname", *WeekDayNameFull(now->tm_wday)));
+ stringTokens.insert(pair<string,string>("daynameshort", *WeekDayName(now->tm_wday)));
+ stringTokens.insert(pair<string,string>("time", *TimeString(t)));
+
+ ClearViewElement(veDateTime);
+ DrawViewElement(veDateTime, &stringTokens, &intTokens);
+ return true;
+}
+
+bool cDisplayMenuView::DrawColorButtons(void) {
+ if (!ViewElementImplemented(veButtons)) {
+ return false;
+ }
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ stringTokens.insert(pair<string,string>("red", buttonTexts[0]));
+ stringTokens.insert(pair<string,string>("green", buttonTexts[1]));
+ stringTokens.insert(pair<string,string>("yellow", buttonTexts[2]));
+ stringTokens.insert(pair<string,string>("blue", buttonTexts[3]));
+
+ int colorKeys[4] = { Setup.ColorKey0, Setup.ColorKey1, Setup.ColorKey2, Setup.ColorKey3 };
+
+ for (int button = 1; button < 5; button++) {
+ string red = *cString::sprintf("red%d", button);
+ string green = *cString::sprintf("green%d", button);
+ string yellow = *cString::sprintf("yellow%d", button);
+ string blue = *cString::sprintf("blue%d", button);
+ bool isRed = false;
+ bool isGreen = false;
+ bool isYellow = false;
+ bool isBlue = false;
+ switch (colorKeys[button-1]) {
+ case 0:
+ isRed = true;
+ break;
+ case 1:
+ isGreen = true;
+ break;
+ case 2:
+ isYellow = true;
+ break;
+ case 3:
+ isBlue = true;
+ break;
+ default:
+ break;
+ }
+ intTokens.insert(pair<string, int>(red, isRed));
+ intTokens.insert(pair<string, int>(green, isGreen));
+ intTokens.insert(pair<string, int>(yellow, isYellow));
+ intTokens.insert(pair<string, int>(blue, isBlue));
+ }
+
+ ClearViewElement(veButtons);
+ DrawViewElement(veButtons, &stringTokens, &intTokens);
+ return true;
+}
+
+bool cDisplayMenuView::DrawMessage(eMessageType type, const char *text) {
+ if (!ViewElementImplemented(veMessage)) {
+ return false;
+ }
+ if (!text) {
+ ClearViewElement(veMessage);
+ return true;
+ }
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ intTokens.insert(pair<string, int>("status", (type == mtStatus) ? true : false));
+ intTokens.insert(pair<string, int>("info", (type == mtInfo) ? true : false));
+ intTokens.insert(pair<string, int>("warning", (type == mtWarning) ? true : false));
+ intTokens.insert(pair<string, int>("error", (type == mtError) ? true : false));
+ stringTokens.insert(pair<string,string>("text", text));
+
+ ClearViewElement(veMessage);
+ DrawViewElement(veMessage, &stringTokens, &intTokens);
+ return true;
+}
+
+void cDisplayMenuView::DrawScrollbar(int numMax, int numDisplayed, int offset) {
+ if (!ViewElementImplemented(veScrollbar)) {
+ return;
+ }
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+ if (numDisplayed < 1)
+ return;
+
+ int barHeight = 0;
+ if (numDisplayed < numMax)
+ barHeight = 1000;
+ else
+ barHeight = (double)numMax * 1000 / (double)numDisplayed;
+
+ int barOffset = (double)offset * 1000 / (double)numDisplayed;
+
+ intTokens.insert(pair<string, int>("height", barHeight));
+ intTokens.insert(pair<string, int>("offset", barOffset));
+
+ ClearViewElement(veScrollbar);
+ DrawViewElement(veScrollbar, &stringTokens, &intTokens);
+}
+
+bool cDisplayMenuView::BackgroundImplemented(void) {
+ if (!ViewElementImplemented(veBackground)) {
+ return false;
+ }
+ return true;
+}
+
+
+void cDisplayMenuView::Action(void) {
+ SetInitFinished();
+ FadeIn();
+ DoFlush();
+}
+
+/************************************************************************
+* cDisplayMenuMainView
+************************************************************************/
+
+cDisplayMenuMainView::cDisplayMenuMainView(cTemplateView *tmplView, bool menuInit) : cDisplayMenuView(tmplView, menuInit) {
+ initial = true;
+ lastSystemLoad = 0.0;
+ InitDevices();
+}
+
+cDisplayMenuMainView::~cDisplayMenuMainView() {
+ CancelSave();
+ FadeOut();
+ delete[] lastSignalStrength;
+ delete[] lastSignalQuality;
+ delete[] recDevices;
+}
+
+void cDisplayMenuMainView::DrawStaticViewElements(void) {
+ DrawTimers();
+ DrawDiscUsage();
+}
+
+bool cDisplayMenuMainView::DrawDynamicViewElements(void) {
+ bool loadChanged = DrawLoad();
+ bool devicesChanged = DrawDevices();
+ initial = false;
+ return loadChanged || devicesChanged;
+
+}
+
+void cDisplayMenuMainView::DrawTimers(void) {
+ if (!ViewElementImplemented(veTimers)) {
+ return;
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ map < string, vector< map< string, string > > > timerLoopTokens;
+ vector< map< string, string > > timers;
+
+ cGlobalSortedTimers SortedTimers;// local and remote timers
+ int numTimers = SortedTimers.Size();
+
+ intTokens.insert(pair<string, int>("numtimers", numTimers));
+
+ int numTimerConflicts = SortedTimers.NumTimerConfilicts();
+ intTokens.insert(pair<string, int>("numtimerconflicts", numTimerConflicts));
+
+ for (int i=0; i<15; i++) {
+ stringstream name;
+ name << "timer" << i+1 << "exists";
+ if (i < numTimers) {
+ intTokens.insert(pair<string, int>(name.str(), true));
+ } else {
+ intTokens.insert(pair<string, int>(name.str(), false));
+ }
+ }
+
+ for (int i = 0; i < numTimers; i++) {
+ if (i >=15)
+ break;
+ map< string, string > timerVals;
+ const cTimer *Timer = SortedTimers[i];
+ const cEvent *event = Timer->Event();
+ if (event) {
+ timerVals.insert(pair< string, string >("timers[title]", event->Title()));
+ } else {
+ const char *File = Setup.FoldersInTimerMenu ? NULL : strrchr(Timer->File(), FOLDERDELIMCHAR);
+ if (File && strcmp(File + 1, TIMERMACRO_TITLE) && strcmp(File + 1, TIMERMACRO_EPISODE))
+ File++;
+ else
+ File = Timer->File();
+ timerVals.insert(pair< string, string >("timers[title]", File));
+ }
+ const cChannel *channel = Timer->Channel();
+ if (channel) {
+ timerVals.insert(pair< string, string >("timers[channelname]", channel->Name()));
+ stringstream chanNum;
+ chanNum << channel->Number();
+ timerVals.insert(pair< string, string >("timers[channelnumber]", chanNum.str()));
+ string channelID = *(channel->GetChannelID().ToString());
+ timerVals.insert(pair< string, string >("timers[channelid]", channelID));
+ bool logoExists = imgCache->LogoExists(channelID);
+ timerVals.insert(pair< string, string >("timers[channellogoexists]", logoExists ? "1" : "0"));
+ } else {
+ timerVals.insert(pair< string, string >("timers[channelname]", ""));
+ timerVals.insert(pair< string, string >("timers[channelnumber]", "0"));
+ timerVals.insert(pair< string, string >("timers[channelid]", ""));
+ timerVals.insert(pair< string, string >("timers[channellogoexists]", "0"));
+ }
+
+ timerVals.insert(pair< string, string >("timers[recording]", Timer->Recording() ? "1" : "0"));
+
+ cString timerDate("");
+ if (Timer->Recording()) {
+ timerDate = cString::sprintf("-%s", *TimeString(Timer->StopTime()));
+ } else {
+ time_t Now = time(NULL);
+ cString Today = WeekDayName(Now);
+ cString Time = TimeString(Timer->StartTime());
+ cString Day = WeekDayName(Timer->StartTime());
+ if (Timer->StartTime() > Now + 6 * SECSINDAY) {
+ time_t ttm = Timer->StartTime();
+ struct tm * timerTime = localtime(&ttm);
+ timerDate = cString::sprintf("%02d.%02d %s", timerTime->tm_mday, timerTime->tm_mon + 1, *Time);
+ } else if (strcmp(Day, Today) != 0)
+ timerDate = cString::sprintf("%s %s", *Day, *Time);
+ else
+ timerDate = Time;
+ if (Timer->Flags() & tfVps)
+ timerDate = cString::sprintf("VPS %s", *timerDate);
+ }
+ timerVals.insert(pair< string, string >("timers[datetime]", *timerDate));
+
+ timers.push_back(timerVals);
+ }
+
+ timerLoopTokens.insert(pair< string, vector< map< string, string > > >("timers", timers));
+
+ ClearViewElement(veTimers);
+ DrawViewElement(veTimers, &stringTokens, &intTokens, &timerLoopTokens);
+}
+
+void cDisplayMenuMainView::DrawDiscUsage(void) {
+ if (!ViewElementImplemented(veDiscUsage)) {
+ return;
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ string vdrUsageString = *cVideoDiskUsage::String();
+ int discUsage = cVideoDiskUsage::UsedPercent();
+ bool discAlert = (discUsage > 95) ? true : false;
+ string freeTime = *cString::sprintf("%02d:%02d", cVideoDiskUsage::FreeMinutes() / 60, cVideoDiskUsage::FreeMinutes() % 60);
+ int freeGB = cVideoDiskUsage::FreeMB() / 1024;
+
+ intTokens.insert(pair<string, int>("usedpercent", discUsage));
+ intTokens.insert(pair<string, int>("freepercent", 100-discUsage));
+ intTokens.insert(pair<string, int>("discalert", discAlert));
+ intTokens.insert(pair<string, int>("freegb", freeGB));
+ stringTokens.insert(pair<string,string>("freetime", freeTime));
+ stringTokens.insert(pair<string,string>("vdrusagestring", vdrUsageString));
+
+ ClearViewElement(veDiscUsage);
+ DrawViewElement(veDiscUsage, &stringTokens, &intTokens);
+}
+
+void cDisplayMenuMainView::InitDevices(void) {
+ int numDevices = cDevice::NumDevices();
+ lastSignalStrength = new int[numDevices];
+ lastSignalQuality = new int[numDevices];
+ recDevices = new bool[numDevices];
+ for (int i=0; i<numDevices; i++) {
+ lastSignalStrength[i] = 0;
+ lastSignalQuality[i] = 0;
+ recDevices[i] = false;
+ }
+}
+
+bool cDisplayMenuMainView::DrawLoad(void) {
+ if (!ViewElementImplemented(veSystemLoad)) {
+ return false;
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ double systemLoad;
+ if (getloadavg(&systemLoad, 1) > 0) {
+ if (lastSystemLoad == systemLoad) {
+ return false;
+ }
+ string load = *cString::sprintf("%.2f", systemLoad);
+ stringTokens.insert(pair<string,string>("load", load));
+ lastSystemLoad = systemLoad;
+ }
+
+ ClearViewElement(veSystemLoad);
+ DrawViewElement(veSystemLoad, &stringTokens, &intTokens);
+
+ return true;
+}
+
+bool cDisplayMenuMainView::DrawDevices(void) {
+ if (!ViewElementImplemented(veDevices)) {
+ return false;
+ }
+ int numDevices = cDevice::NumDevices();
+ if (!initial) {
+ //check if drawing is necessary
+ bool changed = false;
+ for (int i = 0; i < numDevices; i++) {
+ const cDevice *device = cDevice::GetDevice(i);
+ if (!device || !device->NumProvidedSystems()) {
+ continue;
+ }
+ if ((device->SignalStrength() != lastSignalStrength[i]) || (device->SignalQuality() != lastSignalQuality[i])) {
+ changed = true;
+ break;
+ }
+ }
+ if (!changed) {
+ return false;
+ }
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ map < string, vector< map< string, string > > > deviceLoopTokens;
+ vector< map< string, string > > devices;
+
+ //check device which currently displays live tv
+ int deviceLiveTV = -1;
+ cDevice *primaryDevice = cDevice::PrimaryDevice();
+ if (primaryDevice) {
+ if (!primaryDevice->Replaying() || primaryDevice->Transferring())
+ deviceLiveTV = cDevice::ActualDevice()->DeviceNumber();
+ else
+ deviceLiveTV = primaryDevice->DeviceNumber();
+ }
+
+ //check currently recording devices
+ for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) {
+ if (!timer->Recording()) {
+ continue;
+ }
+ if (cRecordControl *RecordControl = cRecordControls::GetRecordControl(timer)) {
+ const cDevice *recDevice = RecordControl->Device();
+ if (recDevice) {
+ recDevices[recDevice->DeviceNumber()] = true;
+ }
+ }
+ }
+ int actualNumDevices = 0;
+ for (int i = 0; i < numDevices; i++) {
+ const cDevice *device = cDevice::GetDevice(i);
+ if (!device || !device->NumProvidedSystems()) {
+ continue;
+ }
+ actualNumDevices++;
+ map< string, string > deviceVals;
+ stringstream strNum;
+ strNum << actualNumDevices;
+ deviceVals.insert(pair< string, string >("devices[num]", strNum.str()));
+ deviceVals.insert(pair< string, string >("devices[type]", *(device->DeviceType())));
+ cCamSlot *camSlot = device->CamSlot();
+ int camNumber = -1;
+ if (camSlot) {
+ camNumber = camSlot->SlotNumber();
+ deviceVals.insert(pair< string, string >("devices[hascam]", "1"));
+ } else {
+ deviceVals.insert(pair< string, string >("devices[hascam]", "0"));
+ }
+ int signalStrength = device->SignalStrength();
+ int signalQuality = device->SignalQuality();
+ stringstream strCamNumber;
+ strCamNumber << camNumber;
+ deviceVals.insert(pair< string, string >("devices[cam]", strCamNumber.str()));
+ stringstream strStrength;
+ strStrength << signalStrength;
+ deviceVals.insert(pair< string, string >("devices[signalstrength]", strStrength.str()));
+ stringstream strQuality;
+ strQuality << signalQuality;
+ deviceVals.insert(pair< string, string >("devices[signalquality]", strQuality.str()));
+
+ deviceVals.insert(pair< string, string >("devices[livetv]", i == deviceLiveTV ? "1" : "0"));
+ deviceVals.insert(pair< string, string >("devices[recording]", recDevices[i] ? "1" : "0"));
+
+ const cChannel *channel = device->GetCurrentlyTunedTransponder();
+ const cSource *source = (channel) ? Sources.Get(channel->Source()) : NULL;
+ if (channel && channel->Number() > 0) {
+ stringstream strChanNum;
+ strChanNum << channel->Number();
+ deviceVals.insert(pair< string, string >("devices[channelnumber]", strChanNum.str()));
+ deviceVals.insert(pair< string, string >("devices[channelname]", channel->Name()));
+ deviceVals.insert(pair< string, string >("devices[channelid]", *(channel->GetChannelID().ToString())));
+ deviceVals.insert(pair< string, string >("devices[istuned]", "1"));
+ } else {
+ deviceVals.insert(pair< string, string >("devices[channelnumber]", "0"));
+ deviceVals.insert(pair< string, string >("devices[channelname]", ""));
+ deviceVals.insert(pair< string, string >("devices[channelid]", ""));
+ deviceVals.insert(pair< string, string >("devices[istuned]", "0"));
+ }
+
+ deviceVals.insert(pair< string, string >("devices[source]", source ? source->Description() : ""));
+
+ devices.push_back(deviceVals);
+
+ lastSignalStrength[i] = signalStrength;
+ lastSignalQuality[i] = signalQuality;
+ }
+ deviceLoopTokens.insert(pair< string, vector< map< string, string > > >("devices", devices));
+
+ intTokens.insert(pair<string, int>("numdevices", actualNumDevices));
+
+ ClearViewElement(veDevices);
+ DrawViewElement(veDevices, &stringTokens, &intTokens, &deviceLoopTokens);
+ return true;
+}
+
+/************************************************************************
+* cDisplayMenuSchedulesView
+************************************************************************/
+
+cDisplayMenuSchedulesView::cDisplayMenuSchedulesView(cTemplateView *tmplView, eMenuCategory menuCat, bool menuInit) : cDisplayMenuView(tmplView, menuInit) {
+ cat = menuCat;
+ channel = NULL;
+}
+
+cDisplayMenuSchedulesView::~cDisplayMenuSchedulesView() {
+ CancelSave();
+ FadeOut();
+}
+
+bool cDisplayMenuSchedulesView::DrawHeader(void) {
+ if (!ViewElementImplemented(veHeader)) {
+ return false;
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ intTokens.insert(pair<string,int>("whatson", (cat == mcSchedule) ? true: false));
+ intTokens.insert(pair<string,int>("whatsonnow", (cat == mcScheduleNow) ? true: false));
+ intTokens.insert(pair<string,int>("whatsonnext", (cat == mcScheduleNext) ? true: false));
+
+ stringTokens.insert(pair<string,string>("title", menuTitle));
+ stringTokens.insert(pair<string,string>("vdrversion", VDRVERSION));
+ if (channel) {
+ stringTokens.insert(pair<string,string>("channelnumber", *cString::sprintf("%d", channel->Number())));
+ stringTokens.insert(pair<string,string>("channelname", channel->Name()));
+ stringTokens.insert(pair<string,string>("channelid", *(channel->GetChannelID().ToString())));
+
+ }
+ ClearViewElement(veHeader);
+ DrawViewElement(veHeader, &stringTokens, &intTokens);
+ return true;
+} \ No newline at end of file
diff --git a/views/displaymenuview.h b/views/displaymenuview.h
new file mode 100644
index 0000000..52f5361
--- /dev/null
+++ b/views/displaymenuview.h
@@ -0,0 +1,60 @@
+#ifndef __DISPLAYMENUVIEW_H
+#define __DISPLAYMENUVIEW_H
+
+#include "../libtemplate/template.h"
+#include "displaymenulistview.h"
+
+class cDisplayMenuView : public cView {
+protected:
+ eMenuCategory cat;
+ string menuTitle;
+ string *buttonTexts;
+ virtual void Action(void);
+public:
+ cDisplayMenuView(cTemplateView *tmplView, bool menuInit);
+ virtual ~cDisplayMenuView();
+ void SetMenuCat(eMenuCategory newCat) { cat = newCat; };
+ void SetTitle(const char *title) {menuTitle = title; };
+ virtual void SetChannel(const cChannel *channel) {};
+ void SetButtonTexts(string *buttonTexts) { this->buttonTexts = buttonTexts; };
+ bool DrawBackground(void);
+ virtual bool DrawHeader(void);
+ bool DrawDateTime(void);
+ bool DrawColorButtons(void);
+ bool DrawMessage(eMessageType type, const char *text);
+ void DrawScrollbar(int numMax, int numDisplayed, int offset);
+ virtual void DrawStaticViewElements(void) {};
+ virtual bool DrawDynamicViewElements(void) { return false; };
+ bool BackgroundImplemented(void);
+};
+
+class cDisplayMenuMainView : public cDisplayMenuView {
+private:
+ bool initial;
+ int* lastSignalStrength;
+ int* lastSignalQuality;
+ double lastSystemLoad;
+ bool* recDevices;
+ void DrawTimers(void);
+ void DrawDiscUsage(void);
+ bool DrawLoad(void);
+ void InitDevices(void);
+ bool DrawDevices(void);
+public:
+ cDisplayMenuMainView(cTemplateView *tmplView, bool menuInit);
+ virtual ~cDisplayMenuMainView();
+ void DrawStaticViewElements(void);
+ bool DrawDynamicViewElements(void);
+};
+
+class cDisplayMenuSchedulesView : public cDisplayMenuView {
+private:
+ const cChannel *channel;
+public:
+ cDisplayMenuSchedulesView(cTemplateView *tmplView, eMenuCategory menuCat, bool menuInit);
+ virtual ~cDisplayMenuSchedulesView();
+ void SetChannel(const cChannel *channel) { this->channel = channel; };
+ bool DrawHeader(void);
+};
+
+#endif //__DISPLAYMENUVIEW_H
diff --git a/views/displaymessageview.c b/views/displaymessageview.c
new file mode 100644
index 0000000..f4cedc2
--- /dev/null
+++ b/views/displaymessageview.c
@@ -0,0 +1,49 @@
+#define __STL_CONFIG_H
+#include <vdr/menu.h>
+#include "displaymessageview.h"
+
+cDisplayMessageView::cDisplayMessageView(cTemplateView *tmplView) : cView(tmplView) {
+ DeleteOsdOnExit();
+ SetFadeTime(tmplView->GetNumericParameter(ptFadeTime));
+}
+
+cDisplayMessageView::~cDisplayMessageView() {
+ CancelSave();
+ FadeOut();
+}
+
+bool cDisplayMessageView::createOsd(void) {
+ cRect osdSize = tmplView->GetOsdSize();
+ bool ok = CreateOsd(cOsd::OsdLeft() + osdSize.X(),
+ cOsd::OsdTop() + osdSize.Y(),
+ osdSize.Width(),
+ osdSize.Height());
+ return ok;
+}
+
+void cDisplayMessageView::DrawBackground(void) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+ DrawViewElement(veBackground, &stringTokens, &intTokens);
+}
+
+void cDisplayMessageView::DrawMessage(eMessageType type, const char *text) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ stringTokens.insert(pair<string,string>("text", text));
+
+ intTokens.insert(pair<string,int>("status", (type == mtStatus) ? true : false));
+ intTokens.insert(pair<string,int>("info", (type == mtInfo) ? true : false));
+ intTokens.insert(pair<string,int>("warning", (type == mtWarning) ? true : false));
+ intTokens.insert(pair<string,int>("error", (type == mtError) ? true : false));
+
+ DrawViewElement(veMessage, &stringTokens, &intTokens);
+}
+
+void cDisplayMessageView::Action(void) {
+ SetInitFinished();
+ FadeIn();
+ DoFlush();
+ cView::Action();
+}
diff --git a/views/displaymessageview.h b/views/displaymessageview.h
new file mode 100644
index 0000000..1bcc908
--- /dev/null
+++ b/views/displaymessageview.h
@@ -0,0 +1,19 @@
+#ifndef __DISPLAYMESSAGEVIEW_H
+#define __DISPLAYMESSAGEVIEW_H
+
+#include "../libtemplate/template.h"
+#include "view.h"
+
+class cDisplayMessageView : public cView {
+private:
+ virtual void Action(void);
+public:
+ cDisplayMessageView(cTemplateView *tmplView);
+ virtual ~cDisplayMessageView();
+ bool createOsd(void);
+ void DrawBackground(void);
+ void DrawMessage(eMessageType type, const char *text);
+ void DoFadeIn(void) { Start(); };
+ void Flush(void) { DoFlush(); };
+};
+#endif //__DISPLAYMESSAGEVIEW_H
diff --git a/views/displayreplayview.c b/views/displayreplayview.c
new file mode 100644
index 0000000..bea64b7
--- /dev/null
+++ b/views/displayreplayview.c
@@ -0,0 +1,376 @@
+#define __STL_CONFIG_H
+#include <vdr/menu.h>
+#include "../services/scraper2vdr.h"
+#include "displayreplayview.h"
+#include "../libcore/helpers.h"
+
+cDisplayReplayView::cDisplayReplayView(cTemplateView *tmplView) : cView(tmplView) {
+ lastDate = "";
+ DeleteOsdOnExit();
+ SetFadeTime(tmplView->GetNumericParameter(ptFadeTime));
+}
+
+cDisplayReplayView::~cDisplayReplayView() {
+ CancelSave();
+ FadeOut();
+}
+
+bool cDisplayReplayView::createOsd(void) {
+ cRect osdSize = tmplView->GetOsdSize();
+ bool ok = CreateOsd(cOsd::OsdLeft() + osdSize.X(),
+ cOsd::OsdTop() + osdSize.Y(),
+ osdSize.Width(),
+ osdSize.Height());
+ return ok;
+}
+
+void cDisplayReplayView::DrawBackground(bool modeOnly) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+ if (modeOnly)
+ DrawViewElement(veBackgroundModeOnly, &stringTokens, &intTokens);
+ else
+ DrawViewElement(veBackground, &stringTokens, &intTokens);
+}
+
+void cDisplayReplayView::DrawDate(bool modeOnly) {
+ if (modeOnly)
+ return;
+ if (!ViewElementImplemented(veDateTime)) {
+ return;
+ }
+ cString curDate = DayDateTime();
+ if (strcmp(curDate, lastDate)) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ time_t t = time(0); // get time now
+ struct tm * now = localtime(&t);
+
+ intTokens.insert(pair<string, int>("year", now->tm_year + 1900));
+ intTokens.insert(pair<string, int>("day", now->tm_mday));
+
+ char monthname[20];
+ char monthshort[10];
+ strftime(monthshort, sizeof(monthshort), "%b", now);
+ strftime(monthname, sizeof(monthname), "%B", now);
+ stringTokens.insert(pair<string,string>("monthname", monthname));
+ stringTokens.insert(pair<string,string>("monthnameshort", monthshort));
+ stringTokens.insert(pair<string,string>("month", *cString::sprintf("%02d", now->tm_mon + 1)));
+ stringTokens.insert(pair<string,string>("dayleadingzero", *cString::sprintf("%02d", now->tm_mday)));
+ stringTokens.insert(pair<string,string>("dayname", *WeekDayNameFull(now->tm_wday)));
+ stringTokens.insert(pair<string,string>("daynameshort", *WeekDayName(now->tm_wday)));
+ stringTokens.insert(pair<string,string>("time", *TimeString(t)));
+
+ ClearViewElement(veDateTime);
+ DrawViewElement(veDateTime, &stringTokens, &intTokens);
+
+ lastDate = curDate;
+ }
+}
+
+void cDisplayReplayView::DrawTitle(const cRecording *recording) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ const char *recName = NULL;
+ const cRecordingInfo *recInfo = recording->Info();
+ if (recInfo) {
+ recName = recInfo->Title();
+ }
+ if (!recName)
+ recName = recording->Name();
+ string recShortText = recInfo->ShortText() ? recInfo->ShortText() : "";
+ string recDate = *ShortDateString(recording->Start());
+ string recTime = *TimeString(recording->Start());
+
+ stringTokens.insert(pair<string,string>("rectitle", recName ? recName : ""));
+ stringTokens.insert(pair<string,string>("recsubtitle", recShortText));
+ stringTokens.insert(pair<string,string>("recdate", recDate));
+ stringTokens.insert(pair<string,string>("rectime", recTime));
+
+ DrawViewElement(veRecTitle, &stringTokens, &intTokens);
+}
+
+void cDisplayReplayView::DrawRecordingInformation(const cRecording *recording) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ int screenWidth = 0;
+ int screenHeight = 0;
+ double aspect = 0;
+ cDevice::PrimaryDevice()->GetVideoSize(screenWidth, screenHeight, aspect);
+ bool isHD = false;
+ string resName = GetScreenResolutionString(screenWidth, screenHeight, &isHD);
+ bool isWideScreen = false;
+ string aspectName = GetScreenAspectString(aspect, &isWideScreen);
+
+ intTokens.insert(pair<string,int>("screenwidth", screenWidth));
+ intTokens.insert(pair<string,int>("screenheight", screenHeight));
+ intTokens.insert(pair<string,int>("isHD", isHD));
+ intTokens.insert(pair<string,int>("isWideScreen", isWideScreen));
+ stringTokens.insert(pair<string,string>("resolution", resName));
+ stringTokens.insert(pair<string,string>("aspect", aspectName));
+
+ ClearViewElement(veRecInfo);
+ DrawViewElement(veRecInfo, &stringTokens, &intTokens);
+}
+
+void cDisplayReplayView::DrawScraperContent(const cRecording *recording) {
+ if (!recording)
+ return;
+
+ if (!ViewElementImplemented(veScraperContent)) {
+ return;
+ }
+
+ static cPlugin *pScraper = GetScraperPlugin();
+ if (!pScraper) {
+ return;
+ }
+
+ ScraperGetPosterBannerV2 call;
+ call.event = NULL;
+ call.recording = recording;
+ if (pScraper->Service("GetPosterBannerV2", &call)) {
+ int mediaWidth = 0;
+ int mediaHeight = 0;
+ std::string mediaPath = "";
+ bool isBanner = false;
+
+ if ((call.type == tSeries) && call.banner.path.size() > 0) {
+ mediaWidth = call.banner.width;
+ mediaHeight = call.banner.height;
+ mediaPath = call.banner.path;
+ isBanner = true;
+ } else if (call.type == tMovie && call.poster.path.size() > 0 && call.poster.height > 0) {
+ mediaWidth = call.poster.width;
+ mediaHeight = call.poster.height;
+ mediaPath = call.poster.path;
+ } else
+ return;
+
+ map < string, int > intTokens;
+ map < string, string > stringTokens;
+ intTokens.insert(pair<string,int>("mediawidth", mediaWidth));
+ intTokens.insert(pair<string,int>("mediaheight", mediaHeight));
+ intTokens.insert(pair<string,int>("isbanner", isBanner));
+ stringTokens.insert(pair<string,string>("mediapath", mediaPath));
+ ClearViewElement(veScraperContent);
+ DrawViewElement(veScraperContent, &stringTokens, &intTokens);
+ }
+}
+
+void cDisplayReplayView::DrawCurrent(const char *current) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+ stringTokens.insert(pair<string,string>("reccurrent", current));
+
+ ClearViewElement(veRecCurrent);
+ DrawViewElement(veRecCurrent, &stringTokens, &intTokens);
+}
+
+void cDisplayReplayView::DrawTotal(const char *total) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+ stringTokens.insert(pair<string,string>("rectotal", total));
+
+ ClearViewElement(veRecTotal);
+ DrawViewElement(veRecTotal, &stringTokens, &intTokens);
+}
+
+void cDisplayReplayView::DrawProgressBar(int current, int total) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+ intTokens.insert(pair<string,int>("current", current));
+ intTokens.insert(pair<string,int>("total", total));
+ stringTokens.insert(pair<string,string>("dummy", ""));
+ ClearViewElement(veRecProgressBar);
+ DrawViewElement(veRecProgressBar, &stringTokens, &intTokens);
+}
+
+void cDisplayReplayView::DrawMarks(const cMarks *marks, int total) {
+ if (!marks)
+ return;
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+ map < string, vector< map< string, string > > > loopTokens;
+ vector< map< string, string > > markTokens;
+ stringstream tot;
+ tot << total;
+
+ bool isStartMark = true;
+ for (const cMark *m = marks->First(); m; m = marks->Next(m)) {
+ map< string, string > markVals;
+ stringstream pos;
+ pos << m->Position();
+ markVals.insert(pair< string, string >("marks[position]", pos.str()));
+ markVals.insert(pair< string, string >("marks[total]", tot.str()));
+ markVals.insert(pair< string, string >("marks[startmark]", isStartMark ? "1" : "0"));
+ const cMark *m2 = marks->Next(m);
+ if (m2) {
+ stringstream posNext;
+ posNext << m2->Position();
+ markVals.insert(pair< string, string >("marks[endposition]", posNext.str()));
+ } else {
+ markVals.insert(pair< string, string >("marks[endposition]", tot.str()));
+ }
+ isStartMark = !isStartMark;
+ markTokens.push_back(markVals);
+ }
+ loopTokens.insert(pair< string, vector< map< string, string > > >("marks", markTokens));
+
+ ClearViewElement(veCuttingMarks);
+ DrawViewElement(veCuttingMarks, &stringTokens, &intTokens, &loopTokens);
+}
+
+void cDisplayReplayView::DrawControlIcons(bool play, bool forward, int speed, bool modeOnly) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ bool isPlay = false;
+ bool isPause = false;
+ bool isFF = false;
+ bool isFF1x = false;
+ bool isFF2x = false;
+ bool isFF3x = false;
+ bool isRew = false;
+ bool isRew1x = false;
+ bool isRew2x = false;
+ bool isRew3x = false;
+
+ if (speed == -1) {
+ if (play) {
+ isPlay = true;
+ } else {
+ isPause = true;
+ }
+ } else if (forward) {
+ if (!play) {
+ isPause = true;
+ }
+ if (speed == 1) {
+ isFF1x = true;
+ } else if (speed == 2) {
+ isFF2x = true;
+ } else if (speed == 3) {
+ isFF3x = true;
+ } else {
+ isFF = true;
+ }
+ } else {
+ if (!play) {
+ isPause = true;
+ }
+ if (speed == 1) {
+ isRew1x = true;
+ } else if (speed == 2) {
+ isRew2x = true;
+ } else if (speed == 3) {
+ isRew3x = true;
+ } else {
+ isRew = true;
+ }
+ }
+ intTokens.insert(pair<string,int>("play", isPlay));
+ intTokens.insert(pair<string,int>("pause", isPause));
+ intTokens.insert(pair<string,int>("forward", isFF));
+ intTokens.insert(pair<string,int>("forward1x", isFF1x));
+ intTokens.insert(pair<string,int>("forward2x", isFF2x));
+ intTokens.insert(pair<string,int>("forward3x", isFF3x));
+ intTokens.insert(pair<string,int>("rewind", isRew));
+ intTokens.insert(pair<string,int>("rewind1x", isRew1x));
+ intTokens.insert(pair<string,int>("rewind2x", isRew2x));
+ intTokens.insert(pair<string,int>("rewind3x", isRew3x));
+
+ if (modeOnly) {
+ ClearViewElement(veControlIconsModeOnly);
+ DrawViewElement(veControlIconsModeOnly, &stringTokens, &intTokens);
+ } else {
+ ClearViewElement(veControlIcons);
+ DrawViewElement(veControlIcons, &stringTokens, &intTokens);
+ }
+}
+
+void cDisplayReplayView::DrawJump(const char *jump) {
+ if (!jump) {
+ ClearViewElement(veRecJump);
+ return;
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+ stringTokens.insert(pair<string,string>("jump", jump));
+
+ ClearViewElement(veRecJump);
+ DrawViewElement(veRecJump, &stringTokens, &intTokens);
+}
+
+void cDisplayReplayView::DrawMessage(eMessageType type, const char *text) {
+ if (!text) {
+ ClearViewElement(veMessage);
+ }
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ stringTokens.insert(pair<string,string>("text", text));
+
+ intTokens.insert(pair<string,int>("status", (type == mtStatus) ? true : false));
+ intTokens.insert(pair<string,int>("info", (type == mtInfo) ? true : false));
+ intTokens.insert(pair<string,int>("warning", (type == mtWarning) ? true : false));
+ intTokens.insert(pair<string,int>("error", (type == mtError) ? true : false));
+
+ ClearViewElement(veMessage);
+ DrawViewElement(veMessage, &stringTokens, &intTokens);
+}
+
+
+void cDisplayReplayView::Action(void) {
+ SetInitFinished();
+ FadeIn();
+ DoFlush();
+ cView::Action();
+}
+
+string cDisplayReplayView::GetScreenResolutionString(int width, int height, bool *isHD) {
+ string name = "";
+ switch (width) {
+ case 1920:
+ case 1440:
+ name = "hd1080i";
+ *isHD = true;
+ break;
+ case 1280:
+ if (height == 720)
+ name = "hd720p";
+ else
+ name = "hd1080i";
+ *isHD = true;
+ break;
+ case 720:
+ name = "sd576i";
+ break;
+ default:
+ name = "sd576i";
+ break;
+ }
+ return name;
+}
+
+string cDisplayReplayView::GetScreenAspectString(double aspect, bool *isWideScreen) {
+ string name = "";
+ *isWideScreen = false;
+ if (aspect == 4.0/3.0) {
+ name = "4:3";
+ *isWideScreen = false;
+ } else if (aspect == 16.0/9.0) {
+ name = "16:9";
+ *isWideScreen = true;
+ } else if (aspect == 2.21) {
+ name = "21:9";
+ *isWideScreen = true;
+ }
+ return name;
+} \ No newline at end of file
diff --git a/views/displayreplayview.h b/views/displayreplayview.h
new file mode 100644
index 0000000..9c81917
--- /dev/null
+++ b/views/displayreplayview.h
@@ -0,0 +1,32 @@
+#ifndef __DISPLAYREPLAYVIEW_H
+#define __DISPLAYREPLAYVIEW_H
+
+#include "../libtemplate/template.h"
+#include "view.h"
+
+class cDisplayReplayView : public cView {
+private:
+ cString lastDate;
+ string GetScreenResolutionString(int width, int height, bool *isHD);
+ string GetScreenAspectString(double aspect, bool *isWideScreen);
+ virtual void Action(void);
+public:
+ cDisplayReplayView(cTemplateView *tmplView);
+ virtual ~cDisplayReplayView();
+ bool createOsd(void);
+ void DrawBackground(bool modeOnly);
+ void DrawDate(bool modeOnly);
+ void DrawTitle(const cRecording *recording);
+ void DrawRecordingInformation(const cRecording *recording);
+ void DrawScraperContent(const cRecording *recording);
+ void DrawCurrent(const char *current);
+ void DrawTotal(const char *total);
+ void DrawProgressBar(int current, int total);
+ void DrawMarks(const cMarks *marks, int total);
+ void DrawControlIcons(bool play, bool forward, int speed, bool modeOnly);
+ void DrawJump(const char *jump);
+ void DrawMessage(eMessageType type, const char *text);
+ void DoFadeIn(void) { Start(); };
+ void Flush(void) { DoFlush(); };
+};
+#endif //__DISPLAYREPLAYVIEW_H
diff --git a/views/displayvolumeview.c b/views/displayvolumeview.c
new file mode 100644
index 0000000..e3700dd
--- /dev/null
+++ b/views/displayvolumeview.c
@@ -0,0 +1,55 @@
+#define __STL_CONFIG_H
+#include <vdr/menu.h>
+#include "displayvolumeview.h"
+
+cDisplayVolumeView::cDisplayVolumeView(cTemplateView *tmplView) : cView(tmplView) {
+ volumeLast = -1;
+ muteLast = false;
+ DeleteOsdOnExit();
+ SetFadeTime(tmplView->GetNumericParameter(ptFadeTime));
+}
+
+cDisplayVolumeView::~cDisplayVolumeView() {
+ CancelSave();
+ FadeOut();
+}
+
+bool cDisplayVolumeView::createOsd(void) {
+ cRect osdSize = tmplView->GetOsdSize();
+ bool ok = CreateOsd(cOsd::OsdLeft() + osdSize.X(),
+ cOsd::OsdTop() + osdSize.Y(),
+ osdSize.Width(),
+ osdSize.Height());
+ return ok;
+}
+
+void cDisplayVolumeView::DrawBackground(void) {
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+ DrawViewElement(veBackground, &stringTokens, &intTokens);
+}
+
+void cDisplayVolumeView::DrawVolume(int current, int total, bool mute) {
+ if ((volumeLast == current) && (muteLast == mute))
+ return;
+ volumeLast = current;
+ muteLast = mute;
+
+ map < string, string > stringTokens;
+ map < string, int > intTokens;
+
+ intTokens.insert(pair<string,int>("volume", current));
+ intTokens.insert(pair<string,int>("maxvolume", total));
+ intTokens.insert(pair<string,int>("volumepercent", (double)current *100 / (double)total));
+ intTokens.insert(pair<string,int>("mute", mute));
+
+ ClearViewElement(veVolume);
+ DrawViewElement(veVolume, &stringTokens, &intTokens);
+}
+
+void cDisplayVolumeView::Action(void) {
+ SetInitFinished();
+ FadeIn();
+ DoFlush();
+ cView::Action();
+}
diff --git a/views/displayvolumeview.h b/views/displayvolumeview.h
new file mode 100644
index 0000000..544426e
--- /dev/null
+++ b/views/displayvolumeview.h
@@ -0,0 +1,21 @@
+#ifndef __DISPLAYVOLUMEVIEW_H
+#define __DISPLAYVOLUMEVIEW_H
+
+#include "../libtemplate/template.h"
+#include "view.h"
+
+class cDisplayVolumeView : public cView {
+private:
+ int volumeLast;
+ bool muteLast;
+ virtual void Action(void);
+public:
+ cDisplayVolumeView(cTemplateView *tmplView);
+ virtual ~cDisplayVolumeView();
+ bool createOsd(void);
+ void DrawBackground(void);
+ void DrawVolume(int current, int total, bool mute);
+ void DoFadeIn(void) { Start(); };
+ void Flush(void) { DoFlush(); };
+};
+#endif //__DISPLAYVOLUMEVIEW_H
diff --git a/views/view.c b/views/view.c
new file mode 100644
index 0000000..3b72253
--- /dev/null
+++ b/views/view.c
@@ -0,0 +1,809 @@
+#include "view.h"
+#include "../config.h"
+#include "../libcore/helpers.h"
+#include "../libcore/imageloader.h"
+
+using namespace std;
+
+cView::cView(cTemplateView *tmplView) : cPixmapContainer(tmplView->GetNumPixmaps()) {
+ this->tmplView = tmplView;
+ tvScaled = tmplView->GetScalingWindow(scalingWindow);
+ if (tvScaled) {
+ cDevice::PrimaryDevice()->ScaleVideo(scalingWindow);
+ }
+ tmplItem = NULL;
+ tmplTab = NULL;
+ Init();
+}
+
+cView::cView(cTemplateViewElement *tmplItem) : cPixmapContainer(tmplItem->GetNumPixmaps()) {
+ this->tmplItem = tmplItem;
+ tmplView = NULL;
+ tmplTab = NULL;
+ tvScaled = false;
+ Init();
+}
+
+cView::cView(cTemplateViewTab *tmplTab) : cPixmapContainer(1) {
+ this->tmplTab = tmplTab;
+ tmplView = NULL;
+ tmplItem = NULL;
+ tvScaled = false;
+ Init();
+}
+
+cView::~cView() {
+ if (tvScaled) {
+ cDevice::PrimaryDevice()->ScaleVideo(cRect::Null);
+ }
+}
+
+void cView::Init(void) {
+ viewInit = true;
+ scrolling = false;
+ veScroll = veUndefined;
+ scrollingPix = -1;
+ scrollOrientation = orHorizontal;
+ scrollDelay = 0;
+ scrollMode = smNone;
+ scrollSpeed = ssMedium;
+ currentlyScrolling = false;
+}
+
+void cView::Action(void) {
+ if (scrolling) {
+ DoSleep(scrollDelay);
+ if (scrollOrientation == orHorizontal) {
+ ActivateScrolling();
+ ScrollHorizontal(scrollingPix, scrollDelay, scrollSpeed, scrollMode);
+ } else {
+ ScrollVertical(scrollingPix, scrollDelay, scrollSpeed);
+ }
+ }
+}
+
+void cView::Stop(void) {
+ CancelSave();
+}
+
+/********************************************************************************
+* Protected Functions
+********************************************************************************/
+
+void cView::DrawViewElement(eViewElement ve, map <string,string> *stringTokens, map <string,int> *intTokens, map < string, vector< map< string, string > > > *loopTokens) {
+ //setting correct ViewElement, depending which constructor was used
+ cTemplateViewElement *viewElement;
+ if (tmplItem && ve == veMenuCurrentItemDetail) {
+ viewElement = tmplItem;
+ } else if (tmplView) {
+ viewElement = tmplView->GetViewElement(ve);
+ }
+ if (!viewElement)
+ return;
+
+ if (viewElement->DebugTokens()) {
+ DebugTokens(tmplView ? (tmplView->GetViewElementName(ve)) : "current view", stringTokens, intTokens, loopTokens);
+ }
+
+ //iterate through pixmaps of viewelement
+ int pixCurrent = viewElement->GetPixOffset();
+ if (pixCurrent < 0)
+ return;
+ viewElement->InitIterator();
+ cTemplatePixmap *pix = NULL;
+ while(pix = viewElement->GetNextPixmap()) {
+ //reset Template
+ pix->ClearDynamicParameters();
+ //create Pixmap if already fully parsed
+ if (!PixmapExists(pixCurrent) && pix->Ready() && pix->DoExecute() && !pix->Scrolling()) {
+ CreateViewPixmap(pixCurrent, pix);
+ }
+ //check if pixmap needs dynamic parameters
+ if ((!pix->Ready() || !pix->DoExecute()) && !pix->Scrolling()) {
+ //parse dynamic parameters and initiate functions
+ pix->ParseDynamicParameters(intTokens, true);
+ if (pix->Ready() && pix->DoExecute()) {
+ CreateViewPixmap(pixCurrent, pix);
+ }
+ } else {
+ //parse dynamic parameters but not initiate functions
+ pix->ParseDynamicParameters(intTokens, false);
+ }
+ //if pixmap still not valid, skip
+ if (!pix->Ready() && !pix->Scrolling()) {
+ pixCurrent++;
+ continue;
+ }
+ //if condition for pixmap set, check if cond is true
+ if (!pix->DoExecute()) {
+ pixCurrent++;
+ continue;
+ }
+ //parse dynamic tokens of pixmap functions
+ pix->ClearDynamicFunctionParameters();
+ pix->ParseDynamicFunctionParameters(stringTokens, intTokens);
+
+ if (!PixmapExists(pixCurrent) && pix->Scrolling()) {
+ cSize drawportSize;
+ scrolling = pix->CalculateDrawPortSize(drawportSize, loopTokens);
+ if (scrolling) {
+ CreateScrollingPixmap(pixCurrent, pix, drawportSize);
+ pix->SetScrollingTextWidth();
+ veScroll = ve;
+ scrollingPix = pixCurrent;
+ scrollOrientation = pix->GetNumericParameter(ptOrientation);
+ scrollMode = pix->GetNumericParameter(ptScrollMode);
+ scrollDelay = pix->GetNumericParameter(ptDelay);
+ scrollSpeed = pix->GetNumericParameter(ptScrollSpeed);
+ } else {
+ CreateViewPixmap(pixCurrent, pix);
+ }
+ }
+ if (pix->DoDebug()) {
+ pix->Debug();
+ }
+
+ DrawPixmap(pixCurrent, pix, loopTokens);
+ pixCurrent++;
+ }
+}
+
+void cView::ClearViewElement(eViewElement ve) {
+ if (!tmplView)
+ return;
+ cTemplateViewElement *viewElement = tmplView->GetViewElement(ve);
+ if (!viewElement)
+ return;
+ int pixCurrent = viewElement->GetPixOffset();
+ if (pixCurrent < 0)
+ return;
+ cTemplatePixmap *pix = NULL;
+ viewElement->InitIterator();
+ while(pix = viewElement->GetNextPixmap()) {
+ Fill(pixCurrent, clrTransparent);
+ pixCurrent++;
+ }
+}
+
+void cView::ActivateScrolling(void) {
+ if (veScroll == veUndefined)
+ return;
+ cTemplateViewElement *scrollViewElement = NULL;
+ if (tmplView) {
+ scrollViewElement = tmplView->GetViewElement(veScroll);
+ }
+ if (!scrollViewElement)
+ return;
+
+ ClearViewElement(veScroll);
+ currentlyScrolling = true;
+
+ int pixCurrent = scrollViewElement->GetPixOffset();
+ if (pixCurrent < 0)
+ return;
+ scrollViewElement->InitIterator();
+ cTemplatePixmap *pix = NULL;
+ while(pix = scrollViewElement->GetNextPixmap()) {
+ DrawPixmap(pixCurrent, pix);
+ pixCurrent++;
+ }
+}
+
+bool cView::ViewElementImplemented(eViewElement ve) {
+ return tmplView->GetNumPixmapsViewElement(ve);
+}
+
+void cView::CreateViewPixmap(int num, cTemplatePixmap *pix, cRect *size) {
+ cRect pixSize;
+ if (size) {
+ pixSize = *size;
+ } else {
+ pixSize = pix->GetPixmapSize();
+ }
+ int layer = pix->GetNumericParameter(ptLayer);
+ int transparency = pix->GetNumericParameter(ptTransparency);
+ SetTransparency(num, transparency);
+ CreatePixmap(num, layer, pixSize);
+}
+
+void cView::CreateScrollingPixmap(int num, cTemplatePixmap *pix, cSize &drawportSize) {
+ cRect pixViewPort = pix->GetPixmapSize();
+ cRect drawPort;
+ drawPort.SetX(0);
+ drawPort.SetY(0);
+ drawPort.SetWidth(drawportSize.Width());
+ drawPort.SetHeight(drawportSize.Height());
+ int layer = pix->GetNumericParameter(ptLayer);
+ int transparency = pix->GetNumericParameter(ptTransparency);
+ SetTransparency(num, transparency);
+ CreatePixmap(num, layer, pixViewPort, drawPort);
+}
+
+void cView::DrawPixmap(int num, cTemplatePixmap *pix, map < string, vector< map< string, string > > > *loopTokens, bool flushPerLoop) {
+ pix->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = pix->GetNextFunction()) {
+ eFuncType type = func->GetType();
+ if (func->DoDebug()) {
+ func->Debug();
+ }
+ if (!func->DoExecute()) {
+ continue;
+ }
+ switch (type) {
+ case ftFill:
+ DoFill(num, func);
+ break;
+ case ftDrawText:
+ DoDrawText(num, func);
+ break;
+ case ftDrawTextBox: {
+ int floating = func->GetNumericParameter(ptFloat);
+ if (floating > flNone) {
+ DoDrawFloatingTextBox(num, func);
+ } else {
+ DoDrawTextBox(num, func);
+ }
+ break; }
+ case ftDrawRectangle:
+ DoDrawRectangle(num, func);
+ break;
+ case ftDrawEllipse:
+ DoDrawEllipse(num, func);
+ break;
+ case ftDrawImage:
+ DoDrawImage(num, func);
+ break;
+ case ftLoop:
+ if (loopTokens)
+ DrawLoop(num, func, loopTokens);
+ break;
+ default:
+ break;
+ }
+ if (flushPerLoop) {
+ DoFlush();
+ }
+ }
+}
+
+void cView::DrawLoop(int numPixmap, cTemplateFunction *func, map < string, vector< map< string, string > > > *loopTokens) {
+ cTemplateLoopFunction *loopFunc = dynamic_cast<cTemplateLoopFunction*>(func);
+ if (!loopFunc)
+ return;
+
+ int loopX0 = loopFunc->GetNumericParameter(ptX);
+ if (loopX0 < 0) loopX0 = 0;
+ int loopY0 = loopFunc->GetNumericParameter(ptY);
+ if (loopY0 < 0) loopY0 = 0;
+ int orientation = loopFunc->GetNumericParameter(ptOrientation);
+ int loopWidth = loopFunc->GetNumericParameter(ptWidth);
+ if (loopWidth <= 0)
+ loopWidth = loopFunc->GetContainerWidth();
+ int loopHeight = loopFunc->GetNumericParameter(ptHeight);
+ if (loopHeight <= 0)
+ loopHeight = loopFunc->GetContainerHeight();
+ int columnWidth = loopFunc->GetNumericParameter(ptColumnWidth);
+ int rowHeight = loopFunc->GetNumericParameter(ptRowHeight);
+ int overflow = loopFunc->GetNumericParameter(ptOverflow);
+ int maxItems = loopFunc->GetNumericParameter(ptNumElements);
+
+ int x0 = loopX0;
+ int y0 = loopY0;
+
+ string loopTokenName = loopFunc->GetParameter(ptName);
+
+ map < string, vector< map< string, string > > >::iterator hit = loopTokens->find(loopTokenName);
+ if (hit == loopTokens->end())
+ return;
+ vector< map<string,string> > loopToken = hit->second;
+ int lineNumber=0;
+ for (vector< map<string,string> >::iterator line = loopToken.begin(); line != loopToken.end(); line++) {
+ //check overflow behaviour
+ if (overflow == otCut) {
+ if (orientation == orHorizontal) {
+ if (lineNumber * columnWidth > loopWidth) {
+ return;
+ }
+ } else if (orientation == orVertical) {
+ if (lineNumber * rowHeight > loopHeight) {
+ return;
+ }
+ }
+ } else if (overflow == otWrap && orientation == orHorizontal) {
+ if (x0 + columnWidth > loopWidth) {
+ x0 = loopX0;
+ if (rowHeight > 0) {
+ y0 += rowHeight;
+ } else {
+ y0 += loopFunc->GetLoopElementsHeight();
+ }
+ }
+ }
+ map<string,string> tokens = *line;
+ loopFunc->ClearDynamicParameters();
+ loopFunc->ParseDynamicParameters(&tokens);
+ loopFunc->InitIterator();
+ cTemplateFunction *func = NULL;
+ while(func = loopFunc->GetNextFunction()) {
+ //do debug?
+ if (func->DoDebug())
+ func->Debug();
+ //check if set condition is true
+ if (!func->DoExecute()) {
+ continue;
+ }
+ //execute
+ eFuncType type = func->GetType();
+ switch (type) {
+ case ftDrawText:
+ DoDrawText(numPixmap, func, x0, y0);
+ break;
+ case ftDrawTextBox:
+ DoDrawTextBox(numPixmap, func, x0, y0);
+ break;
+ case ftDrawRectangle:
+ DoDrawRectangle(numPixmap, func, x0, y0);
+ break;
+ case ftDrawEllipse:
+ DoDrawEllipse(numPixmap, func, x0, y0);
+ break;
+ case ftDrawImage:
+ DoDrawImage(numPixmap, func, x0, y0);
+ break;
+ default:
+ break;
+ }
+ }
+ //calculate position of next loop element
+ if (orientation == orHorizontal) {
+ if (columnWidth > 0) {
+ x0 += columnWidth;
+ } else {
+ x0 += loopFunc->GetLoopElementsWidth();
+ }
+ } else if (orientation == orVertical) {
+ if (rowHeight > 0) {
+ y0 += rowHeight;
+ } else {
+ y0 += loopFunc->GetLoopElementsHeight();
+ }
+ }
+ lineNumber++;
+ //DoFlush();
+ }
+}
+
+void cView::DebugTokens(string viewElement, map<string,string> *stringTokens, map<string,int> *intTokens, map < string, vector< map< string, string > > > *loopTokens) {
+ esyslog("skindesigner: ------------------------------ Tokens for %s:", viewElement.c_str());
+ if (stringTokens) {
+ for (map<string,string>::iterator st = stringTokens->begin(); st != stringTokens->end(); st++) {
+ esyslog("skindesigner: string var \"%s\" = \"%s\"", (st->first).c_str(), (st->second).c_str());
+ }
+ }
+ if (intTokens) {
+ for (map<string,int>::iterator it = intTokens->begin(); it != intTokens->end(); it++) {
+ esyslog("skindesigner: int var \"%s\" = %d", (it->first).c_str(), it->second);
+ }
+ }
+ if (loopTokens) {
+ for(map < string, vector< map< string, string > > >::iterator it1 = loopTokens->begin(); it1 != loopTokens->end(); it1++) {
+ int line = 0;
+ string tokenName = it1->first;
+ vector< map<string,string> > tokens = it1->second;
+ esyslog("skindesigner: loop token %s", tokenName.c_str());
+ for (vector< map<string,string> >::iterator it2 = tokens.begin(); it2 != tokens.end(); it2++) {
+ esyslog("skindesigner: loop tokens line %d:", line++);
+ map<string,string> element = *it2;
+ for (map<string,string>::iterator el = element.begin(); el != element.end(); el++) {
+ esyslog("skindesigner: name: %s, value: %s", (el->first).c_str(), (el->second).c_str());
+ }
+ }
+ }
+ }
+}
+
+/*****************************************************************
+* Private Functions
+*****************************************************************/
+
+void cView::DoFill(int num, cTemplateFunction *func) {
+ tColor col = func->GetColorParameter(ptColor);
+ Fill(num, col);
+}
+
+void cView::DoDrawText(int num, cTemplateFunction *func, int x0, int y0) {
+ int x = func->GetNumericParameter(ptX);
+ if (x < 0) x = 0;
+ x += x0;
+ int y = func->GetNumericParameter(ptY);
+ if (y < 0) y = 0;
+ y += y0;
+ cPoint pos(x,y);
+ string fontName = func->GetFontName();
+ int fontSize = func->GetNumericParameter(ptFontSize);
+ tColor clr = func->GetColorParameter(ptColor);
+ tColor clrBack = clrTransparent;
+ string text = "";
+ if (!currentlyScrolling) {
+ text = func->GetText(true);
+ } else {
+ text = func->GetText(false);
+ }
+ DrawText(num, pos, text.c_str(), clr, clrBack, fontName, fontSize);
+}
+
+void cView::DoDrawTextBox(int num, cTemplateFunction *func, int x0, int y0) {
+ string text = func->GetText(false);
+ if (text.size() < 3)
+ return;
+ int x = func->GetNumericParameter(ptX);
+ int y = func->GetNumericParameter(ptY);
+ if (x < 0) x = 0;
+ x += x0;
+ if (y < 0) y = 0;
+ y += y0;
+ int width = func->GetNumericParameter(ptWidth);
+ int height = func->GetNumericParameter(ptHeight);
+ string fontName = func->GetFontName();
+ int fontSize = func->GetNumericParameter(ptFontSize);
+ int align = func->GetNumericParameter(ptAlign);
+ int maxLines = func->GetNumericParameter(ptMaxLines);
+ tColor clr = func->GetColorParameter(ptColor);
+ tColor clrBack = clrTransparent;
+ const cFont *font = fontManager->Font(fontName, fontSize);
+ if (!font)
+ return;
+ cTextWrapper wrapper;
+ wrapper.Set(text.c_str(), font, width);
+ int fontHeight = fontManager->Height(fontName, fontSize);
+ int lines = wrapper.Lines();
+ int yLine = y;
+ for (int line=0; line < lines; line++) {
+ int xLine = x;
+ if (align == alCenter) {
+ int textWidth = font->Width(wrapper.GetLine(line));
+ xLine += (width - textWidth)/2;
+ } else if (align == alRight) {
+ int textWidth = font->Width(wrapper.GetLine(line));
+ xLine += (width - textWidth);
+ }
+ cPoint pos(xLine, yLine);
+ if (maxLines > 0 && line == maxLines-1) {
+ string lastLine = wrapper.GetLine(line);
+ if (lines > maxLines) {
+ lastLine += "...";
+ }
+ DrawText(num, pos, lastLine.c_str(), clr, clrBack, fontName, fontSize);
+ break;
+ } else if (height > 0 && yLine - y + 2*fontHeight > height) {
+ DrawText(num, pos, "...", clr, clrBack, fontName, fontSize);
+ break;
+ }
+ DrawText(num, pos, wrapper.GetLine(line), clr, clrBack, fontName, fontSize);
+ yLine += fontHeight;
+ }
+}
+
+void cView::DoDrawFloatingTextBox(int num, cTemplateFunction *func) {
+ string text = func->GetText(false);
+ if (text.size() < 3)
+ return;
+ int x = func->GetNumericParameter(ptX);
+ int y = func->GetNumericParameter(ptY);
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+ int width = func->GetNumericParameter(ptWidth);
+ int height = func->GetNumericParameter(ptHeight);
+ string fontName = func->GetFontName();
+ int fontSize = func->GetNumericParameter(ptFontSize);
+ tColor clr = func->GetColorParameter(ptColor);
+ tColor clrBack = clrTransparent;
+ const cFont *font = fontManager->Font(fontName, fontSize);
+ if (!font)
+ return;
+ int floatType = func->GetNumericParameter(ptFloat);
+ int floatWidth = func->GetNumericParameter(ptFloatWidth);
+ int floatHeight = func->GetNumericParameter(ptFloatHeight);
+
+ cTextWrapper wTextTall;
+ cTextWrapper wTextFull;
+
+ int fontHeight = fontManager->Height(fontName, fontSize);
+ int linesNarrow = floatHeight / fontHeight;
+ int widthNarrow = width - floatWidth;
+ int linesDrawn = 0;
+ int curY = 0;
+ bool drawNarrow = true;
+
+ splitstring s(text.c_str());
+ std::vector<std::string> flds = s.split('\n', 1);
+
+ if (flds.size() < 1)
+ return;
+
+ std::stringstream sstrTextTall;
+ std::stringstream sstrTextFull;
+
+ for (int i=0; i<flds.size(); i++) {
+ if (!flds[i].size()) {
+ //empty line
+ linesDrawn++;
+ curY += fontHeight;
+ if (drawNarrow)
+ sstrTextTall << "\n";
+ else
+ sstrTextFull << "\n";
+ } else {
+ cTextWrapper wrapper;
+ if (drawNarrow) {
+ wrapper.Set((flds[i].c_str()), font, widthNarrow);
+ int newLines = wrapper.Lines();
+ //check if wrapper fits completely into narrow area
+ if (linesDrawn + newLines < linesNarrow) {
+ for (int line = 0; line < wrapper.Lines(); line++) {
+ sstrTextTall << wrapper.GetLine(line) << " ";
+ }
+ sstrTextTall << "\n";
+ linesDrawn += newLines;
+ } else {
+ //this wrapper has to be splitted
+ for (int line = 0; line < wrapper.Lines(); line++) {
+ if (line + linesDrawn < linesNarrow) {
+ sstrTextTall << wrapper.GetLine(line) << " ";
+ } else {
+ sstrTextFull << wrapper.GetLine(line) << " ";
+ }
+ }
+ sstrTextFull << "\n";
+ drawNarrow = false;
+ }
+ } else {
+ wrapper.Set((flds[i].c_str()), font, width);
+ for (int line = 0; line < wrapper.Lines(); line++) {
+ sstrTextFull << wrapper.GetLine(line) << " ";
+ }
+ sstrTextFull << "\n";
+ }
+ }
+ }
+ //VDRs textwrapper swallows linebreaks at the end, so we have to fix that manually
+ string textTall = sstrTextTall.str();
+ size_t posLastCarriageReturn = textTall.find_last_not_of("\n");
+
+ int numLinesToAddAtTall = 0;
+ if (posLastCarriageReturn != string::npos && (posLastCarriageReturn < textTall.size() - 1)) {
+ numLinesToAddAtTall = textTall.size() - posLastCarriageReturn - 2;
+ }
+
+ wTextTall.Set(textTall.c_str(), font, widthNarrow);
+ wTextFull.Set(sstrTextFull.str().c_str(), font, width);
+
+ int textLinesTall = wTextTall.Lines();
+ int textLinesFull = wTextFull.Lines();
+
+ int textXTall = x;
+ if (floatType == flTopLeft)
+ textXTall = x + floatWidth;
+
+ int yLine = y;
+ for (int line=0; line < textLinesTall; line++) {
+ cPoint pos(textXTall, yLine);
+ DrawText(num, pos, wTextTall.GetLine(line), clr, clrBack, fontName, fontSize);
+ yLine += fontHeight;
+ }
+
+ if (numLinesToAddAtTall) {
+ yLine += numLinesToAddAtTall * fontHeight;
+ }
+
+ for (int line=0; line < textLinesFull; line++) {
+ cPoint pos(x, yLine);
+ if (height > 0 && yLine - y + 2*fontHeight > height) {
+ DrawText(num, pos, "...", clr, clrBack, fontName, fontSize);
+ break;
+ }
+ DrawText(num, pos, wTextFull.GetLine(line), clr, clrBack, fontName, fontSize);
+ yLine += fontHeight;
+ }
+}
+
+void cView::DoDrawRectangle(int num, cTemplateFunction *func, int x0, int y0) {
+ int x = func->GetNumericParameter(ptX);
+ int y = func->GetNumericParameter(ptY);
+ if (x < 0) x = 0;
+ x += x0;
+ if (y < 0) y = 0;
+ y += y0;
+ int w = func->GetNumericParameter(ptWidth);
+ int h = func->GetNumericParameter(ptHeight);
+ cRect size(x, y, w, h);
+ tColor clr = func->GetColorParameter(ptColor);
+ DrawRectangle(num, size, clr);
+}
+
+void cView::DoDrawEllipse(int num, cTemplateFunction *func, int x0, int y0) {
+ int x = func->GetNumericParameter(ptX);
+ int y = func->GetNumericParameter(ptY);
+ if (x < 0) x = 0;
+ x += x0;
+ if (y < 0) y = 0;
+ y += y0;
+ int w = func->GetNumericParameter(ptWidth);
+ int h = func->GetNumericParameter(ptHeight);
+ cRect size(x, y, w, h);
+ tColor clr = func->GetColorParameter(ptColor);
+ int quadrant = func->GetNumericParameter(ptQuadrant);
+ DrawEllipse(num, size, clr, quadrant);
+}
+
+void cView::DoDrawImage(int num, cTemplateFunction *func, int x0, int y0) {
+ int x = func->GetNumericParameter(ptX);
+ int y = func->GetNumericParameter(ptY);
+ if (x < 0) x = 0;
+ x += x0;
+ if (y < 0) y = 0;
+ y += y0;
+ cPoint pos(x,y);
+ int width = func->GetNumericParameter(ptWidth);
+ int height = func->GetNumericParameter(ptHeight);
+ string path = func->GetImagePath();
+ eImageType type = (eImageType)func->GetNumericParameter(ptImageType);
+ switch (type) {
+ case itChannelLogo: {
+ cImage *logo = imgCache->GetLogo(path, width, height);
+ if (logo) {
+ DrawImage(num, pos, *logo);
+ }
+ break; }
+ case itSepLogo: {
+ cImage *sepLogo = imgCache->GetSeparatorLogo(path, width, height);
+ if (sepLogo) {
+ DrawImage(num, pos, *sepLogo);
+ }
+ break; }
+ case itSkinPart: {
+ cImage *skinpart = imgCache->GetSkinpart(path, width, height);
+ if (skinpart) {
+ DrawImage(num, pos, *skinpart);
+ }
+ break; }
+ case itIcon: {
+ cImage *icon = imgCache->GetIcon(type, path, width, height);
+ if (icon) {
+ DrawImage(num, pos, *icon);
+ }
+ break; }
+ case itMenuIcon: {
+ cImage *icon = imgCache->GetIcon(type, path, width, height);
+ if (icon) {
+ DrawImage(num, pos, *icon);
+ }
+ break; }
+ case itImage: {
+ cImageLoader imgLoader;
+ if (imgLoader.LoadImage(path.c_str(), width, height)) {
+ DrawImage(num, pos, imgLoader.GetImage());
+ }
+ break; }
+ default:
+ break;
+ }
+}
+
+/***********************************************************************
+* cViewListItem
+************************************************************************/
+
+cViewListItem::cViewListItem(cTemplateViewElement *tmplItem) : cView(tmplItem) {
+ pos = -1;
+ numTotal = 0;
+ align = alLeft;
+ listOrientation = orVertical;
+}
+
+cViewListItem::~cViewListItem() {
+
+}
+
+cRect cViewListItem::DrawListItem(map <string,string> *stringTokens, map <string,int> *intTokens) {
+ cRect posItem;
+ if (!tmplItem)
+ return posItem;
+
+ if (tmplItem->DebugTokens()) {
+ DebugTokens("ListItem", stringTokens, intTokens);
+ }
+
+ tmplItem->InitIterator();
+ cTemplatePixmap *pix = NULL;
+ int pixCurrent = 0;
+
+ while(pix = tmplItem->GetNextPixmap()) {
+ SetListElementPosition(pix);
+ if (pixCurrent == 0) {
+ posItem = pix->GetPixmapSize();
+ }
+ if (!PixmapExists(pixCurrent)) {
+ pix->ParseDynamicParameters(intTokens, true);
+ } else {
+ pix->ParseDynamicParameters(intTokens, false);
+ }
+ if (!PixmapExists(pixCurrent) && pix->Ready() && pix->DoExecute() && !pix->Scrolling()) {
+ CreateViewPixmap(pixCurrent, pix);
+ }
+ //if pixmap still not valid, skip
+ if (!pix->Ready() && !pix->Scrolling()) {
+ pixCurrent++;
+ continue;
+ }
+ //if condition for pixmap set, check if cond is true
+ if (!pix->DoExecute()) {
+ pixCurrent++;
+ continue;
+ }
+
+ pix->ClearDynamicFunctionParameters();
+ pix->ParseDynamicFunctionParameters(stringTokens, intTokens);
+
+ if (!PixmapExists(pixCurrent) && pix->Scrolling()) {
+ cSize drawportSize;
+ scrolling = pix->CalculateDrawPortSize(drawportSize);
+ pix->SetScrollingTextWidth();
+ if (scrolling) {
+ CreateScrollingPixmap(pixCurrent, pix, drawportSize);
+ scrollingPix = pixCurrent;
+ scrollOrientation = pix->GetNumericParameter(ptOrientation);
+ scrollMode = pix->GetNumericParameter(ptScrollMode);
+ scrollDelay = pix->GetNumericParameter(ptDelay);
+ scrollSpeed = pix->GetNumericParameter(ptScrollSpeed);
+ } else {
+ CreateViewPixmap(pixCurrent, pix);
+ }
+ }
+ if (pix->DoDebug()) {
+ pix->Debug();
+ }
+ DrawPixmap(pixCurrent, pix);
+ pixCurrent++;
+ }
+ return posItem;
+}
+
+void cViewListItem::ClearListItem(void) {
+ int pixMax = NumPixmaps();
+ for (int pixCurrent = 0; pixCurrent < pixMax; pixCurrent++) {
+ Fill(pixCurrent, clrTransparent);
+ }
+}
+
+void cViewListItem::SetListElementPosition(cTemplatePixmap *pix) {
+ int itemWidth = pix->GetNumericParameter(ptWidth);
+ int itemHeight = pix->GetNumericParameter(ptHeight);
+ int x = 0;
+ int y = 0;
+ if (listOrientation == orHorizontal) {
+ x = container.X();
+ int totalWidth = numTotal * itemWidth;
+ if (align == alCenter) {
+ y += (container.Width() - totalWidth) / 2;
+ } else if (align == alBottom) {
+ y += (container.Width() - totalWidth);
+ }
+ x += pos * itemWidth;
+ y = pix->GetNumericParameter(ptY);
+ } else if (listOrientation == orVertical) {
+ y = container.Y();
+ int totalHeight = numTotal * itemHeight;
+ if (align == alCenter) {
+ y += (container.Height() - totalHeight) / 2;
+ } else if (align == alBottom) {
+ y += (container.Height() - totalHeight);
+ }
+ y += pos * itemHeight;
+ x = pix->GetNumericParameter(ptX);
+ }
+ pix->SetX(x);
+ pix->SetY(y);
+}
+
diff --git a/views/view.h b/views/view.h
new file mode 100644
index 0000000..4609935
--- /dev/null
+++ b/views/view.h
@@ -0,0 +1,72 @@
+#ifndef __VIEW_H
+#define __VIEW_H
+
+#include "string"
+#include "map"
+#include "../libcore/pixmapcontainer.h"
+#include "../libtemplate/template.h"
+
+using namespace std;
+
+class cView : public cPixmapContainer {
+private:
+ void Init(void);
+ void DoFill(int num, cTemplateFunction *func);
+ void DoDrawText(int num, cTemplateFunction *func, int x0 = 0, int y0 = 0);
+ void DoDrawTextBox(int num, cTemplateFunction *func, int x0 = 0, int y0 = 0);
+ void DoDrawFloatingTextBox(int num, cTemplateFunction *func);
+ void DoDrawRectangle(int num, cTemplateFunction *func, int x0 = 0, int y0 = 0);
+ void DoDrawEllipse(int num, cTemplateFunction *func, int x0 = 0, int y0 = 0);
+ void DoDrawImage(int num, cTemplateFunction *func, int x0 = 0, int y0 = 0);
+ void ActivateScrolling(void);
+protected:
+ cTemplateView *tmplView;
+ cTemplateViewElement *tmplItem;
+ cTemplateViewTab *tmplTab;
+ //scaling window
+ cRect scalingWindow;
+ bool tvScaled;
+ bool viewInit;
+ //true if view is scrollable in general
+ bool scrolling;
+ //true if view is actually starting scrolling
+ bool currentlyScrolling;
+ eViewElement veScroll;
+ int scrollingPix;
+ int scrollOrientation;
+ int scrollDelay;
+ int scrollMode;
+ int scrollSpeed;
+ void DrawViewElement(eViewElement ve, map <string,string> *stringTokens = NULL, map <string,int> *intTokens = NULL, map < string, vector< map< string, string > > > *loopTokens = NULL);
+ void ClearViewElement(eViewElement ve);
+ bool ViewElementImplemented(eViewElement ve);
+ void CreateViewPixmap(int num, cTemplatePixmap *pix, cRect *size = NULL);
+ void CreateScrollingPixmap(int num, cTemplatePixmap *pix, cSize &drawportSize);
+ void DrawPixmap(int num, cTemplatePixmap *pix, map < string, vector< map< string, string > > > *loopTokens = NULL, bool flushPerLoop = false);
+ void DrawLoop(int numPixmap, cTemplateFunction *func, map < string, vector< map< string, string > > > *loopTokens);
+ void DebugTokens(string viewElement, map<string,string> *stringTokens, map<string,int> *intTokens, map < string, vector< map< string, string > > > *loopTokens = NULL);
+ virtual void Action(void);
+public:
+ cView(cTemplateView *tmplView);
+ cView(cTemplateViewElement *tmplItem);
+ cView(cTemplateViewTab *tmplTab);
+ virtual ~cView();
+ virtual void Stop(void);
+};
+
+class cViewListItem : public cView {
+protected:
+ int pos;
+ int numTotal;
+ cRect container;
+ int align;
+ int listOrientation;
+ void SetListElementPosition(cTemplatePixmap *pix);
+public:
+ cViewListItem(cTemplateViewElement *tmplItem);
+ virtual ~cViewListItem();
+ cRect DrawListItem(map <string,string> *stringTokens, map <string,int> *intTokens);
+ void ClearListItem(void);
+};
+
+#endif //__VIEW_H \ No newline at end of file