add a global ActionMap
[enigma2.git] / lib / python / Screens / InfoBarGenerics.py
index 45c7745e850ee4be9655678f3c38e7066f454e8e..a627cdb43f2a7c786f38592c41e4cab13ec85df8 100644 (file)
@@ -1,11 +1,14 @@
 from Screen import Screen
 from Components.ActionMap import ActionMap, HelpableActionMap
 from Components.ActionMap import NumberActionMap
-from Components.Label import Label
+from Components.Label import *
+from Components.ProgressBar import *
 from Components.config import configfile, configsequencearg
 from Components.config import config, configElement, ConfigSubsection, configSequence
-from ChannelSelection import ChannelSelection
+from ChannelSelection import ChannelSelection, BouquetSelector
 
+from Components.Pixmap import Pixmap, PixmapConditional
+from Components.BlinkingPixmap import BlinkingPixmapConditional
 from Components.ServiceName import ServiceName
 from Components.EventInfo import EventInfo
 
@@ -15,8 +18,14 @@ from EpgSelection import EPGSelection
 from Screens.MessageBox import MessageBox
 from Screens.Volume import Volume
 from Screens.Mute import Mute
+from Screens.Dish import Dish
 from Screens.Standby import Standby
 from Screens.EventView import EventView
+from Screens.MinuteInput import MinuteInput
+from Components.Harddisk import harddiskmanager
+
+from Tools import Notifications
+from Tools.Directories import *
 
 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
 from enigma import *
@@ -24,22 +33,25 @@ from enigma import *
 import time
 import os
 
+from Components.config import config, currentConfigSelectionElement
+
 # hack alert!
 from Menu import MainMenu, mdom
 
+from GlobalActions import globalActionMap
+
 class InfoBarVolumeControl:
        """Volume control, handles volUp, volDown, volMute actions and display 
        a corresponding dialog"""
+
        def __init__(self):
-               config.audio = ConfigSubsection()
-               config.audio.volume = configElement("config.audio.volume", configSequence, [5], configsequencearg.get("INTEGER", (0, 100)))
+               global globalActionMap
+               globalActionMap.actions["volumeUp"]=self.volUp
+               globalActionMap.actions["volumeDown"]=self.volDown
+               globalActionMap.actions["volumeMute"]=self.volMute
 
-               self["VolumeActions"] = ActionMap( ["InfobarVolumeActions"] ,
-                       {
-                               "volumeUp": self.volUp,
-                               "volumeDown": self.volDown,
-                               "volumeMute": self.volMute,
-                       })
+               config.audio = ConfigSubsection()
+               config.audio.volume = configElement("config.audio.volume", configSequence, [100], configsequencearg.get("INTEGER", (0, 100)))
 
                self.volumeDialog = self.session.instantiateDialog(Volume)
                self.muteDialog = self.session.instantiateDialog(Mute)
@@ -56,18 +68,22 @@ class InfoBarVolumeControl:
                config.audio.volume.save()
                
        def     volUp(self):
+               if (eDVBVolumecontrol.getInstance().isMuted()):
+                       self.volMute()
                eDVBVolumecontrol.getInstance().volumeUp()
                self.volumeDialog.instance.show()
                self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
                self.volSave()
-               self.hideVolTimer.start(3000)
+               self.hideVolTimer.start(3000, True)
 
        def     volDown(self):
+               if (eDVBVolumecontrol.getInstance().isMuted()):
+                       self.volMute()
                eDVBVolumecontrol.getInstance().volumeDown()
                self.volumeDialog.instance.show()
                self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
                self.volSave()
-               self.hideVolTimer.start(3000)
+               self.hideVolTimer.start(3000, True)
                
        def volHide(self):
                self.volumeDialog.instance.hide()
@@ -81,6 +97,11 @@ class InfoBarVolumeControl:
                else:
                        self.muteDialog.instance.hide()
 
+class InfoBarDish:
+       def __init__(self):
+               self.dishDialog = self.session.instantiateDialog(Dish)
+               self.onShown.append(self.dishDialog.instance.hide)
+
 class InfoBarShowHide:
        """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
        fancy animations. """
@@ -96,16 +117,27 @@ class InfoBarShowHide:
                                "hide": self.hide,
                        })
 
-               self.state = self.STATE_HIDDEN
+               self.state = self.STATE_SHOWN
+               
+               self.onExecBegin.append(self.show)
+               self.onClose.append(self.delHideTimer)
                
                self.hideTimer = eTimer()
                self.hideTimer.timeout.get().append(self.doTimerHide)
-               #self.hideTimer.start(1000)
+               self.hideTimer.start(5000, True)
+
+       def delHideTimer(self):
+               del self.hideTimer
 
        def hide(self): 
                self.instance.hide()
+               
+       def show(self):
+               self.state = self.STATE_SHOWN
+               self.hideTimer.start(5000, True)
 
        def doTimerHide(self):
+               self.hideTimer.stop()
                if self.state == self.STATE_SHOWN:
                        self.instance.hide()
                        self.state = self.STATE_HIDDEN
@@ -115,14 +147,12 @@ class InfoBarShowHide:
                        self.instance.hide()
                        #pls check animation support, sorry
 #                      self.startHide()
+                       self.hideTimer.stop()
                        self.state = self.STATE_HIDDEN
-               else:
+               elif self.state == self.STATE_HIDDEN:
                        self.instance.show()
-#                      self.startShow()
-                       self.state = self.STATE_SHOWN
-                       #TODO: make it customizable
-                       self.hideTimer.start(5000)
-
+                       self.show()
+                       
        def startShow(self):
                self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
                self.state = self.STATE_SHOWN
@@ -141,7 +171,7 @@ class NumberZap(Screen):
                self.close(int(self["number"].getText()))
 
        def keyNumberGlobal(self, number):
-               self.Timer.start(3000)          #reset timer
+               self.Timer.start(3000, True)            #reset timer
                self.field = self.field + str(number)
                self["number"].setText(self.field)
                if len(self.field) >= 4:
@@ -150,7 +180,9 @@ class NumberZap(Screen):
        def __init__(self, session, number):
                Screen.__init__(self, session)
                self.field = str(number)
-               
+
+               self["channel"] = Label(_("Channel:"))
+
                self["number"] = Label(self.field)
 
                self["actions"] = NumberActionMap( [ "SetupActions" ], 
@@ -171,7 +203,7 @@ class NumberZap(Screen):
 
                self.Timer = eTimer()
                self.Timer.timeout.get().append(self.keyOK)
-               self.Timer.start(3000)
+               self.Timer.start(3000, True)
 
 class InfoBarPowerKey:
        """ PowerKey stuff - handles the powerkey press and powerkey release actions"""
@@ -179,10 +211,12 @@ class InfoBarPowerKey:
        def __init__(self):
                self.powerKeyTimer = eTimer()
                self.powerKeyTimer.timeout.get().append(self.powertimer)
-               self["PowerKeyActions"] = ActionMap( ["PowerKeyActions"],
+               self["PowerKeyActions"] = HelpableActionMap(self, "PowerKeyActions",
                        {
                                "powerdown": self.powerdown,
                                "powerup": self.powerup,
+                               "discreteStandby": (self.standby, "Go standby"),
+                               "discretePowerOff": (self.quit, "Go to deep standby"),
                        })
 
        def powertimer(self):   
@@ -191,16 +225,20 @@ class InfoBarPowerKey:
        
        def powerdown(self):
                self.standbyblocked = 0
-               self.powerKeyTimer.start(3000)
+               self.powerKeyTimer.start(3000, True)
 
        def powerup(self):
                self.powerKeyTimer.stop()
                if self.standbyblocked == 0:
                        self.standbyblocked = 1
-                       self.session.open(Standby, self)
+                       self.standby()
+
+       def standby(self):
+               self.session.open(Standby, self)
 
        def quit(self):
-               quitMainloop(0)
+               # halt
+               quitMainloop(1)
 
 class InfoBarNumberZap:
        """ Handles an initial number for NumberZapping """
@@ -221,12 +259,53 @@ class InfoBarNumberZap:
 
        def keyNumberGlobal(self, number):
 #              print "You pressed number " + str(number)
-               self.session.openWithCallback(self.numberEntered, NumberZap, number)
+               if number == 0:
+                       self.session.nav.zapLast()
+                       self.instance.show()
+                       self.show()
+               else:
+                       self.session.openWithCallback(self.numberEntered, NumberZap, number)
 
        def numberEntered(self, retval):
 #              print self.servicelist
                if retval > 0:
-                       self.servicelist.zapToNumber(retval)
+                       self.zapToNumber(retval)
+
+       def searchNumberHelper(self, serviceHandler, num, bouquet):
+               servicelist = serviceHandler.list(bouquet)
+               if not servicelist is None:
+                       while num:
+                               serviceIterator = servicelist.getNext()
+                               if not serviceIterator.valid(): #check end of list
+                                       break
+                               if serviceIterator.flags: #assume normal dvb service have no flags set
+                                       continue
+                               num -= 1;
+                       if not num: #found service with searched number ?
+                               return serviceIterator, 0
+               return None, num
+
+       def zapToNumber(self, number):
+               bouquet = self.servicelist.bouquet_root
+               service = None
+               serviceHandler = eServiceCenter.getInstance()
+               if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
+                       service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
+               else:
+                       bouquetlist = serviceHandler.list(bouquet)
+                       if not bouquetlist is None:
+                               while number:
+                                       bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
+                                       if not bouquet.valid(): #check end of list
+                                               break
+                                       if ((bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory):
+                                               continue
+                                       service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
+               if not service is None:
+                       self.session.nav.playService(service) #play service
+                       if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
+                               self.servicelist.setRoot(bouquet)
+                       self.servicelist.setCurrentSelection(service) #select the service in servicelist
 
 class InfoBarChannelSelection:
        """ ChannelSelection - handles the channelSelection dialog and the initial 
@@ -254,17 +333,21 @@ class InfoBarChannelSelection:
        def     zapUp(self):
                self.servicelist.moveUp()
                self.servicelist.zap()
+               self.instance.show()
+               self.show()
 
        def     zapDown(self):
                self.servicelist.moveDown()
                self.servicelist.zap()
-
+               self.instance.show()
+               self.show()
+               
 class InfoBarMenu:
        """ Handles a menu action, to open the (main) menu """
        def __init__(self):
-               self["MenuActions"] = ActionMap( [ "InfobarMenuActions" ]
+               self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions"
                        {
-                               "mainMenu": self.mainMenu,
+                               "mainMenu": (self.mainMenu, "Enter main menu..."),
                        })
 
        def mainMenu(self):
@@ -278,11 +361,77 @@ class InfoBarEPG:
        def __init__(self):
                self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions", 
                        {
-                               "showEPGList": (self.showEPGList, _("show EPG...")),
+                               "showEPGList": (self.showEPG, _("show EPG...")),
                        })
 
+       def showEPG(self):
+               if currentConfigSelectionElement(config.usage.epgtoggle) == "yes":
+                       self.openSingleServiceEPG()
+               else:
+                       self.showEPGList()
+
        def showEPGList(self):
+               bouquets = self.servicelist.getBouquetList()
+               if bouquets is None:
+                       cnt = 0
+               else:
+                       cnt = len(bouquets)
+               if cnt > 1: # show bouquet list
+                       self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
+               elif cnt == 1: # add to only one existing bouquet
+                       self.openBouquetEPG(bouquets[0][1])
+               else: #no bouquets so we open single epg
+                       self.openSingleEPGSelector(self.session.nav.getCurrentlyPlayingServiceReference())
+
+       def bouquetEPGCallback(self, info):
+               if info:
+                       self.openSingleServiceEPG()
+       
+       def singleEPGCallback(self, info):
+               if info:
+                       self.showEPGList()
+                       
+       def openEventView(self):
+               try:
+                       self.epglist = [ ]
+                       service = self.session.nav.getCurrentService()
+                       info = service.info()
+                       ptr=info.getEvent(0)
+                       if ptr:
+                               self.epglist.append(ptr)
+                       ptr=info.getEvent(1)
+                       if ptr:
+                               self.epglist.append(ptr)
+                       if len(self.epglist) > 0:
+                               self.session.open(EventView, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
+               except:
+                       pass
+                       
+       def openSingleServiceEPG(self):
                ref=self.session.nav.getCurrentlyPlayingServiceReference()
+               ptr=eEPGCache.getInstance()
+               if ptr.startTimeQuery(ref) != -1:
+                       self.session.openWithCallback(self.singleEPGCallback, EPGSelection, ref)
+               else: # try to show now/next
+                       print 'no epg for service', ref.toString()
+
+       
+       def openBouquetEPG(self, bouquet):
+               ptr=eEPGCache.getInstance()
+               services = [ ]
+               servicelist = eServiceCenter.getInstance().list(bouquet)
+               if not servicelist is None:
+                       while True:
+                               service = servicelist.getNext()
+                               if not service.valid(): #check if end of list
+                                       break
+                               if service.flags: #ignore non playable services
+                                       continue
+                               services.append(ServiceReference(service))
+               if len(services):
+                       self.session.openWithCallback(self.bouquetEPGCallback, EPGSelection, services)
+
+       def openSingleEPGSelector(self, ref):
                ptr=eEPGCache.getInstance()
                if ptr.startTimeQuery(ref) != -1:
                        self.session.open(EPGSelection, ref)
@@ -303,13 +452,57 @@ class InfoBarEPG:
                        except:
                                pass
 
-       def eventViewCallback(self, setEvent, val): #used for now/next displaying
+       def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
                if len(self.epglist) > 1:
                        tmp = self.epglist[0]
                        self.epglist[0]=self.epglist[1]
                        self.epglist[1]=tmp
                        setEvent(self.epglist[0])
 
+from math import log
+
+class InfoBarTuner:
+       """provides a snr/agc/ber display"""
+       def __init__(self):
+               self["snr"] = Label()
+               self["agc"] = Label()
+               self["ber"] = Label()
+               self["snr_percent"] = Label()
+               self["agc_percent"] = Label()
+               self["ber_count"] = Label()
+               self["snr_progress"] = ProgressBar()
+               self["agc_progress"] = ProgressBar()
+               self["ber_progress"] = ProgressBar()
+               self.timer = eTimer()
+               self.timer.timeout.get().append(self.updateTunerInfo)
+               self.timer.start(1000)
+
+       def calc(self,val):
+               if not val:
+                       return 0
+               if val < 2500:
+                       return (long)(log(val)/log(2))
+               return val*100/65535
+
+       def updateTunerInfo(self):
+               if self.instance.isVisible():
+                       service = self.session.nav.getCurrentService()
+                       snr=0
+                       agc=0
+                       ber=0
+                       if service is not None:
+                               feinfo = service.frontendStatusInfo()
+                               if feinfo is not None:
+                                       ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
+                                       snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
+                                       agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
+                       self["snr_percent"].setText("%d%%"%(snr))
+                       self["agc_percent"].setText("%d%%"%(agc))
+                       self["ber_count"].setText("%d"%(ber))
+                       self["snr_progress"].setValue(snr)
+                       self["agc_progress"].setValue(agc)
+                       self["ber_progress"].setValue(self.calc(ber))
+
 class InfoBarEvent:
        """provides a current/next event info display"""
        def __init__(self):
@@ -326,25 +519,120 @@ class InfoBarServiceName:
        def __init__(self):
                self["ServiceName"] = ServiceName(self.session.nav)
 
-class InfoBarPVR:
-       """handles PVR specific actions like seeking, pause"""
+class InfoBarSeek:
+       """handles actions like seeking, pause"""
+       
+       # ispause, isff, issm, skip
+       SEEK_STATE_PLAY = (0, 0, 0, 0)
+       SEEK_STATE_PAUSE = (1, 0, 0, 0)
+       SEEK_STATE_FF_2X = (0, 2, 0, 0)
+       SEEK_STATE_FF_4X = (0, 4, 0, 0)
+       SEEK_STATE_FF_8X = (0, 8, 0, 0)
+       SEEK_STATE_FF_32X = (0, 4, 0, 32)
+       SEEK_STATE_FF_64X = (0, 4, 0, 64)
+       SEEK_STATE_FF_128X = (0, 4, 0, 128)
+       
+       SEEK_STATE_BACK_4X = (0, 0, 0, -4)
+       SEEK_STATE_BACK_32X = (0, 0, 0, -32)
+       SEEK_STATE_BACK_64X = (0, 0, 0, -64)
+       SEEK_STATE_BACK_128X = (0, 0, 0, -128)
+       
+       SEEK_STATE_SM_HALF = (0, 0, 2, 0)
+       SEEK_STATE_SM_QUARTER = (0, 0, 4, 0)
+       SEEK_STATE_SM_EIGHTH = (0, 0, 8, 0)
+       
        def __init__(self):
-               self["PVRActions"] = ActionMap( [ "InfobarPVRActions" ]
+               self["SeekActions"] = HelpableActionMap(self, "InfobarSeekActions"
                        {
-                               "pauseService": self.pauseService,
-                               "unPauseService": self.unPauseService,
+                               "pauseService": (self.pauseService, "pause"),
+                               "unPauseService": (self.unPauseService, "continue"),
                                
-                               "seekFwd": self.seekFwd,
-                               "seekBack": self.seekBack,
+                               "seekFwd": (self.seekFwd, "skip forward"),
+                               "seekFwdUp": (self.seekFwdUp, "skip forward"),
+                               "seekBack": (self.seekBack, "skip backward"),
+                               "seekBackUp": (self.seekBackUp, "skip backward"),
                        })
+
+               self.seekstate = self.SEEK_STATE_PLAY
+               self.seekTimer = eTimer()
+               self.seekTimer.timeout.get().append(self.seekTimerFired)
+               self.skipinterval = 500 # 500ms skip interval
+               self.onClose.append(self.delSeekTimer)
                
+               self.fwdtimer = False
+               self.fwdKeyTimer = eTimer()
+               self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
+
+               self.rwdtimer = False
+               self.rwdKeyTimer = eTimer()
+               self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
+       
+       def up(self):
+               pass
+       
+       def down(self):
+               pass
+       
+       def delSeekTimer(self):
+               del self.seekTimer
+       
+       def seekTimerFired(self):
+               self.seekbase += self.skipmode * self.skipinterval
+               
+               # check if we bounced against the beginning of the file
+               if self.seekbase < 0:
+                       self.seekbase = 0;
+                       self.setSeekState(self.SEEK_STATE_PLAY)
+                       
+               self.doSeek(self.seekbase)
+
+       def setSeekState(self, state):
+               oldstate = self.seekstate
+               
+               self.seekstate = state
+
+               service = self.session.nav.getCurrentService()
+               if service is None:
+                       return
+               
+               pauseable = service.pause()
+               
+               for i in range(4):
+                       if oldstate[i] != self.seekstate[i]:
+                               (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion, self.setSkipMode)[i](self.seekstate[i])
+               
+       def setSkipMode(self, skipmode):
+               self.skipmode = skipmode
+               if skipmode == 0:
+                       self.seekTimer.stop()
+               else:
+                       self.seekTimer.start(500)
+               
+               service = self.session.nav.getCurrentService()
+               if service is None:
+                       return
+               
+               seekable = service.seek()
+               if seekable is None:
+                       return
+
+               if skipmode:
+                       seekable.setTrickmode(1)
+               else:
+                       seekable.setTrickmode(0)
+               
+               self.seekbase = seekable.getPlayPosition()[1] / 90
+       
        def pauseService(self):
-               self.session.nav.pause(1)
+               if (self.seekstate == self.SEEK_STATE_PAUSE):
+                       self.unPauseService()
+               else:
+                       self.setSeekState(self.SEEK_STATE_PAUSE);
                
        def unPauseService(self):
-               self.session.nav.pause(0)
+               self.setSeekState(self.SEEK_STATE_PLAY);
        
-       def doSeek(self, dir, seektime):
+       def doSeek(self, seektime):
                service = self.session.nav.getCurrentService()
                if service is None:
                        return
@@ -352,73 +640,232 @@ class InfoBarPVR:
                seekable = service.seek()
                if seekable is None:
                        return
-               seekable.seekRelative(dir, 90 * seektime)
+               seekable.seekTo(90 * seektime)
 
        def seekFwd(self):
-               self.doSeek(+1, 60000)
-       
+               print "start fwd timer"
+               self.fwdtimer = True
+               self.fwdKeyTimer.start(500)
+
        def seekBack(self):
-               self.doSeek(-1, 60000)
+               print "start rewind timer"
+               self.rwdtimer = True
+               self.rwdKeyTimer.start(500)
+
+       def seekFwdUp(self):
+               if self.fwdtimer:
+                       self.fwdKeyTimer.stop()
+                       self.fwdtimer = False
+                       lookup = {
+                                       self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
+                                       self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
+                                       self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
+                                       self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
+                                       self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
+                                       self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
+                                       self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
+                                       self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
+                                       self.SEEK_STATE_BACK_4X: self.SEEK_STATE_PLAY,
+                                       self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_4X,
+                                       self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
+                                       self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
+                                       self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
+                                       self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
+                                       self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
+                               }
+                       self.setSeekState(lookup[self.seekstate]);
+       
+       def seekBackUp(self):
+               if self.rwdtimer:
+                       self.rwdKeyTimer.stop()
+                       self.rwdtimer = False
+               
+                       lookup = {
+                                       self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_4X,
+                                       self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
+                                       self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
+                                       self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
+                                       self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
+                                       self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
+                                       self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
+                                       self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
+                                       self.SEEK_STATE_BACK_4X: self.SEEK_STATE_BACK_32X,
+                                       self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
+                                       self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
+                                       self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
+                                       self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
+                                       self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
+                                       self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
+                               }
+                       self.setSeekState(lookup[self.seekstate]);
+               
+       def fwdTimerFire(self):
+               print "Display seek fwd"
+               self.fwdKeyTimer.stop()
+               self.fwdtimer = False
+               self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
+               
+       def fwdSeekTo(self, minutes):
+               print "Seek", minutes, "minutes forward"
+               if minutes != 0:
+                       service = self.session.nav.getCurrentService()
+                       if service is None:
+                               return
+                       seekable = service.seek()
+                       if seekable is None:
+                               return
+                       seekable.seekRelative(1, minutes * 60 * 90000)
+       
+       def rwdTimerFire(self):
+               self.rwdKeyTimer.stop()
+               self.rwdtimer = False
+               self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
+       
+       def rwdSeekTo(self, minutes):
+               self.fwdSeekTo(0 - minutes)
+
+class InfoBarShowMovies:
+
+       # i don't really like this class. 
+       # it calls a not further specified "movie list" on up/down/movieList,
+       # so this is not moe than an action map
+       def __init__(self):
+               self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions", 
+                       {
+                               "movieList": (self.showMovies, "movie list"),
+                               "up": (self.showMovies, "movie list"),
+                               "down": (self.showMovies, "movie list")
+                       })
+
+class InfoBarTimeshift:
+       def __init__(self):
+               self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions", 
+                       {
+                               "timeshiftStart": (self.startTimeshift, "start timeshift "),
+                               "timeshiftStop": (self.stopTimeshift, "stop timeshift")
+                       })
+               self.tshack = 0
+       
+       def getTimeshift(self):
+               service = self.session.nav.getCurrentService()
+               return service.timeshift()
+
+       def startTimeshift(self):
+               # TODO: check for harddisk! (or do this in the interface? would make
+               # more sense... for example radio could be timeshifted in memory,
+               # and the decision can't be made here)
+               print "enable timeshift"
+               ts = self.getTimeshift()
+               if ts is None:
+                       self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
+                       print "no ts interface"
+                       return
+               print "ok, timeshift enabled"
+               if self.tshack == 0:
+                       ts.startTimeshift()
+                       self.tshack = 1
+               else:
+                       pauseable = self.session.nav.getCurrentService().pause()
+                       pauseable.pause() # switch to record
+
+       def stopTimeshift(self):
+               print "disable timeshift"
+               ts = self.getTimeshift()
+               if ts is None:
+                       return
+               ts.stopTimeshift()
+               self.tshack = 0
+               
+
+from RecordTimer import parseEvent
 
 class InfoBarInstantRecord:
        """Instant Record - handles the instantRecord action in order to 
        start/stop instant records"""
        def __init__(self):
-               self["InstnantRecordActions"] = ActionMap( [ "InfobarInstantRecord" ],
+               self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
                        {
-                               "instantRecord": self.instantRecord,
+                               "instantRecord": (self.instantRecord, "Instant Record..."),
                        })
                self.recording = None
-
+               
+               self["BlinkingPoint"] = BlinkingPixmapConditional()
+               self.onShown.append(self["BlinkingPoint"].hideWidget)
+               self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
+               
        def stopCurrentRecording(self): 
                self.session.nav.RecordTimer.removeEntry(self.recording)
                self.recording = None
-       
+                       
        def startInstantRecording(self):
                serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
-                       
+               
                # try to get event info
-               epg = None
+               event = None
                try:
                        service = self.session.nav.getCurrentService()
                        info = service.info()
                        ev = info.getEvent(0)
-                       epg = ev
+                       event = ev
                except:
                        pass
                
+               if event is not None:
+                       data = parseEvent(event)
+                       begin = data[0]
+                       if begin < time.time():
+                               begin = time.time()
+                       
+                       end = data[1]
+                       if end < begin:
+                               end = begin
+                       
+                       end += 3600 * 10
+                       
+                       data = (begin, end, data[2], data[3], data[4])
+               else:
+                       data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
+               
                # fix me, description. 
-               self.recording = self.session.nav.recordWithTimer(time.time(), time.time() + 3600, serviceref, epg, "instant record")
+               self.recording = self.session.nav.recordWithTimer(serviceref, *data)
                self.recording.dontSave = True
+               
+               #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
+               
+       def isInstantRecordRunning(self):
+               if self.recording != None:
+                       if self.recording.isRunning():
+                               return True
+               return False
 
        def recordQuestionCallback(self, answer):
                if answer == False:
                        return
                
-               if self.recording != None:
+               if self.isInstantRecordRunning():
                        self.stopCurrentRecording()
                else:
                        self.startInstantRecording()
 
        def instantRecord(self):
                try:
-                       stat = os.stat("/hdd/movies")
+                       stat = os.stat(resolveFilename(SCOPE_HDD))
                except:
-                       self.session.open(MessageBox, "No HDD found!")
+                       self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
                        return
        
-               if self.recording != None:
-                       self.session.openWithCallback(self.recordQuestionCallback, MessageBox, "Do you want to stop the current\n(instant) recording?")
+               if self.isInstantRecordRunning():
+                       self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
                else:
-                       self.session.openWithCallback(self.recordQuestionCallback, MessageBox, "Start recording?")
+                       self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
 
 from Screens.AudioSelection import AudioSelection
 
 class InfoBarAudioSelection:
        def __init__(self):
-               self["AudioSelectionAction"] = ActionMap( [ "InfobarAudioSelectionActions" ]
+               self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions"
                        {
-                               "audioSelection": self.audioSelection,
+                               "audioSelection": (self.audioSelection, "Audio Options..."),
                        })
 
        def audioSelection(self):
@@ -427,3 +874,129 @@ class InfoBarAudioSelection:
                n = audio.getNumberOfTracks()
                if n > 0:
                        self.session.open(AudioSelection, audio)
+
+from Screens.SubserviceSelection import SubserviceSelection
+
+class InfoBarSubserviceSelection:
+       def __init__(self):
+               self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
+                       {
+                               "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
+                       })
+
+       def subserviceSelection(self):
+               service = self.session.nav.getCurrentService()
+               subservices = service.subServices()
+               n = subservices.getNumberOfSubservices()
+               if n > 0:
+                       self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
+
+       def subserviceSelected(self, service):
+               if not service is None:
+                       self.session.nav.playService(service)
+
+class InfoBarAdditionalInfo:
+       def __init__(self):
+               self["DolbyActive"] = Pixmap()
+               self["CryptActive"] = Pixmap()
+               self["FormatActive"] = Pixmap()
+               
+               self["ButtonRed"] = PixmapConditional(withTimer = False)
+               self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
+               self.onShown.append(self["ButtonRed"].update)
+               self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
+               self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
+               self.onShown.append(self["ButtonRedText"].update)
+
+               self["ButtonGreen"] = Pixmap()
+               self["ButtonGreenText"] = Label(_("Subservices"))
+
+               self["ButtonYellow"] = PixmapConditional(withTimer = False)
+               self["ButtonYellow"].setConnect(lambda: False)
+
+               self["ButtonBlue"] = PixmapConditional(withTimer = False)
+               self["ButtonBlue"].setConnect(lambda: False)
+
+               self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
+
+       def hideSubServiceIndication(self):
+               self["ButtonGreen"].hideWidget()
+               self["ButtonGreenText"].hide()
+
+       def showSubServiceIndication(self):
+               self["ButtonGreen"].showWidget()
+               self["ButtonGreenText"].show()
+
+       def checkFormat(self, service):
+               info = service.info()
+               if info is not None:
+                       aspect = info.getInfo(iServiceInformation.sAspect)
+                       if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
+                               self["FormatActive"].showWidget()
+                       else:
+                               self["FormatActive"].hideWidget()
+
+       def checkSubservices(self, service):
+               if service.subServices().getNumberOfSubservices() > 0:
+                       self.showSubServiceIndication()
+               else:
+                       self.hideSubServiceIndication()
+
+       def checkDolby(self, service):
+               # FIXME
+               dolby = False
+               audio = service.audioTracks()
+               if audio is not None:
+                       n = audio.getNumberOfTracks()
+                       for x in range(n):
+                               i = audio.getTrackInfo(x)
+                               description = i.getDescription();
+                               if description.find("AC3") != -1 or description.find("DTS") != -1:
+                                       dolby = True
+                                       break
+               if dolby:
+                       self["DolbyActive"].showWidget()
+               else:
+                       self["DolbyActive"].hideWidget()
+
+       def checkCrypted(self, service):
+               info = service.info()
+               if info is not None:
+                       if info.getInfo(iServiceInformation.sIsCrypted) > 0:
+                               self["CryptActive"].showWidget()
+                       else:
+                               self["CryptActive"].hideWidget()
+
+       def gotServiceEvent(self, ev):
+               service = self.session.nav.getCurrentService()
+               if ev == pNavigation.evUpdatedEventInfo:
+                       self.checkSubservices(service)
+                       self.checkFormat(service)
+               elif ev == pNavigation.evUpdatedInfo:
+                       self.checkCrypted(service)
+                       self.checkDolby(service)
+               elif ev == pNavigation.evStopService:
+                       self.hideSubServiceIndication()
+                       self["CryptActive"].hideWidget()
+                       self["DolbyActive"].hideWidget()
+                       self["FormatActive"].hideWidget()
+
+class InfoBarNotifications:
+       def __init__(self):
+               self.onExecBegin.append(self.checkNotifications)
+               Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
+       
+       def checkNotificationsIfExecing(self):
+               if self.execing:
+                       self.checkNotifications()
+
+       def checkNotifications(self):
+               if len(Notifications.notifications):
+                       n = Notifications.notifications[0]
+                       Notifications.notifications = Notifications.notifications[1:]
+                       print "open",n
+                       cb = n[0]
+                       if cb is not None:
+                               self.session.openWithCallback(cb, *n[1:])
+                       else:
+                               self.session.open(*n[1:])