show ChannelSelection on first run (after the start wizard)
[enigma2.git] / lib / python / Screens / InfoBarGenerics.py
index 56158423a96f96786bc3924c230e263731aed948..7a7eb8ff78c3a9cf86cfe1de33d025980763c3c5 100644 (file)
@@ -4,21 +4,25 @@ from Components.ActionMap import NumberActionMap
 from Components.Label import *
 from Components.ProgressBar import *
 from Components.config import configfile, configsequencearg
-from Components.config import config, configElement, ConfigSubsection, configSequence
+from Components.config import config, configElement, ConfigSubsection, configSequence, configElementBoolean
 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, EventInfoProgress
+from Components.Clock import Clock
+from Components.Input import Input
 
 from ServiceReference import ServiceReference
 from EpgSelection import EPGSelection
 
 from Screens.MessageBox import MessageBox
+from Screens.ChoiceBox import ChoiceBox
+from Screens.InputBox import InputBox
 from Screens.Dish import Dish
 from Screens.Standby import Standby
-from Screens.EventView import EventView
+from Screens.EventView import EventViewEPGSelect, EventViewSimple
 from Screens.MinuteInput import MinuteInput
 from Components.Harddisk import harddiskmanager
 
@@ -32,6 +36,7 @@ from enigma import *
 
 import time
 import os
+import bisect
 
 from Components.config import config, currentConfigSelectionElement
 
@@ -41,7 +46,7 @@ from Menu import MainMenu, mdom
 class InfoBarDish:
        def __init__(self):
                self.dishDialog = self.session.instantiateDialog(Dish)
-               self.onShown.append(self.dishDialog.instance.show)
+               self.onLayoutFinish.append(self.dishDialog.show)
 
 class InfoBarShowHide:
        """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
@@ -58,49 +63,63 @@ class InfoBarShowHide:
                                "hide": self.hide,
                        })
 
-               self.state = self.STATE_SHOWN
+               self.__state = self.STATE_SHOWN
+               self.__locked = 0
                
                self.onExecBegin.append(self.show)
-               self.onClose.append(self.delHideTimer)
                
                self.hideTimer = eTimer()
                self.hideTimer.timeout.get().append(self.doTimerHide)
                self.hideTimer.start(5000, True)
+               
+               self.onShow.append(self.__onShow)
+               self.onHide.append(self.__onHide)
 
-       def delHideTimer(self):
-               del self.hideTimer
+       def __onShow(self):
+               self.__state = self.STATE_SHOWN
+               self.startHideTimer()
+       
+       def startHideTimer(self):
+               if self.__state == self.STATE_SHOWN and not self.__locked:
+                       self.hideTimer.start(5000, True)
 
-       def hide(self): 
-               self.instance.hide()
-               
-       def show(self):
-               self.state = self.STATE_SHOWN
-               self.hideTimer.start(5000, True)
+       def __onHide(self):
+               self.__state = self.STATE_HIDDEN
+
+       def doShow(self):
+               self.show()
+               self.startHideTimer()
 
        def doTimerHide(self):
                self.hideTimer.stop()
-               if self.state == self.STATE_SHOWN:
-                       self.instance.hide()
-                       self.state = self.STATE_HIDDEN
+               if self.__state == self.STATE_SHOWN:
+                       self.hide()
 
        def toggleShow(self):
-               if self.state == self.STATE_SHOWN:
-                       self.instance.hide()
-                       #pls check animation support, sorry
-#                      self.startHide()
+               if self.__state == self.STATE_SHOWN:
+                       self.hide()
                        self.hideTimer.stop()
-                       self.state = self.STATE_HIDDEN
-               elif self.state == self.STATE_HIDDEN:
-                       self.instance.show()
+               elif self.__state == self.STATE_HIDDEN:
                        self.show()
-                       
-       def startShow(self):
-               self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
-               self.state = self.STATE_SHOWN
+
+       def lockShow(self):
+               self.__locked = self.__locked + 1
+               if self.execing:
+                       self.show()
+                       self.hideTimer.stop()
        
-       def startHide(self):
-               self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
-               self.state = self.STATE_HIDDEN
+       def unlockShow(self):
+               self.__locked = self.__locked - 1
+               if self.execing:
+                       self.startHideTimer()
+
+#      def startShow(self):
+#              self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
+#              self.__state = self.STATE_SHOWN
+#      
+#      def startHide(self):
+#              self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
+#              self.__state = self.STATE_HIDDEN
 
 class NumberZap(Screen):
        def quit(self):
@@ -184,7 +203,7 @@ class InfoBarPowerKey:
 class InfoBarNumberZap:
        """ Handles an initial number for NumberZapping """
        def __init__(self):
-               self["NumberZapActions"] = NumberActionMap( [ "NumberZapActions"],
+               self["NumberActions"] = NumberActionMap( [ "NumberActions"],
                        {
                                "1": self.keyNumberGlobal,
                                "2": self.keyNumberGlobal,
@@ -202,8 +221,7 @@ class InfoBarNumberZap:
 #              print "You pressed number " + str(number)
                if number == 0:
                        self.servicelist.recallPrevService()
-                       self.instance.show()
-                       self.show()
+                       self.doShow()
                else:
                        self.session.openWithCallback(self.numberEntered, NumberZap, number)
 
@@ -251,41 +269,64 @@ class InfoBarNumberZap:
                        self.servicelist.setCurrentSelection(service) #select the service in servicelist
                        self.servicelist.zap()
 
+config.misc.initialchannelselection = configElementBoolean("config.misc.initialchannelselection", 1);
+
 class InfoBarChannelSelection:
        """ ChannelSelection - handles the channelSelection dialog and the initial 
        channelChange actions which open the channelSelection dialog """
        def __init__(self):
                #instantiate forever
                self.servicelist = self.session.instantiateDialog(ChannelSelection)
+               
+               if config.misc.initialchannelselection.value == 1:
+                       self.onShown.append(self.firstRun)
 
                self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
                        {
                                "switchChannelUp": self.switchChannelUp,
                                "switchChannelDown": self.switchChannelDown,
-                               "zapUp": (self.zapUp, _("next channel")),
-                               "zapDown": (self.zapDown, _("previous channel")),
+                               "zapUp": (self.zapUp, _("previous channel")),
+                               "zapDown": (self.zapDown, _("next channel")),
+                               "historyBack": (self.historyBack, _("previous channel in history")),
+                               "historyNext": (self.historyNext, _("next channel in history"))
                        })
-                       
-       def switchChannelUp(self):      
+
+       def firstRun(self):
+               self.onShown.remove(self.firstRun)
+               config.misc.initialchannelselection.value = 0
+               config.misc.initialchannelselection.save()
+               self.switchChannelDown()
+               
+       def historyBack(self):
+               self.servicelist.historyBack()
+
+       def historyNext(self):
+               self.servicelist.historyNext()
+
+       def switchChannelUp(self):
                self.servicelist.moveUp()
                self.session.execDialog(self.servicelist)
 
-       def switchChannelDown(self):    
+       def switchChannelDown(self):
                self.servicelist.moveDown()
                self.session.execDialog(self.servicelist)
 
-       def     zapUp(self):
+       def zapUp(self):
+               if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
+                       if self.servicelist.inBouquet() and self.servicelist.atBegin():
+                               self.servicelist.prevBouquet()
                self.servicelist.moveUp()
                self.servicelist.zap()
-               self.instance.show()
-               self.show()
+               self.doShow()
 
-       def     zapDown(self):
-               self.servicelist.moveDown()
+       def zapDown(self):
+               if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
+                       self.servicelist.nextBouquet()
+               else:
+                       self.servicelist.moveDown()
                self.servicelist.zap()
-               self.instance.show()
-               self.show()
-               
+               self.doShow()
+
 class InfoBarMenu:
        """ Handles a menu action, to open the (main) menu """
        def __init__(self):
@@ -300,67 +341,54 @@ class InfoBarMenu:
                assert menu.tagName == "menu", "root element in menu must be 'menu'!"
                self.session.open(MainMenu, menu, menu.childNodes)
 
+class InfoBarSimpleEventView:
+       """ Opens the Eventview for now/next """
+       def __init__(self):
+               self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
+                       {
+                               "showEventInfo": (self.openEventView, _("show event details")),
+                       })
+
+       def openEventView(self):
+               self.epglist = [ ]
+               service = self.session.nav.getCurrentService()
+               ref = self.session.nav.getCurrentlyPlayingServiceReference()
+               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(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
+
+       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])
+
 class InfoBarEPG:
        """ EPG - Opens an EPG list when the showEPGList action fires """
        def __init__(self):
                self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions", 
                        {
-                               "showEPGList": (self.showEPG, _("show EPG...")),
+                               "showEventInfo": (self.openEventView, _("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 zapToService(self, service):
+               if not service is None:
+                       if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
+                               self.servicelist.clearPath()
+                               if self.servicelist.bouquet_root != self.epg_bouquet:
+                                       self.servicelist.enterPath(self.servicelist.bouquet_root)
+                               self.servicelist.enterPath(self.epg_bouquet)
+                       self.servicelist.setCurrentSelection(service) #select the service in servicelist
+                       self.servicelist.zap()
 
-       
-       def openBouquetEPG(self, bouquet):
+       def openBouquetEPG(self, bouquet, withCallback=True):
                ptr=eEPGCache.getInstance()
                services = [ ]
                servicelist = eServiceCenter.getInstance().list(bouquet)
@@ -373,28 +401,59 @@ class InfoBarEPG:
                                        continue
                                services.append(ServiceReference(service))
                if len(services):
-                       self.session.openWithCallback(self.bouquetEPGCallback, EPGSelection, services)
+                       self.epg_bouquet = bouquet
+                       if withCallback:
+                               self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
+                       else:
+                               self.session.open(EPGSelection, services, self.zapToService)
 
-       def openSingleEPGSelector(self, ref):
+       def closed(self, ret):
+               if ret:
+                       self.close(ret)
+
+       def openMultiServiceEPG(self, withCallback=True):
+               bouquets = self.servicelist.getBouquetList()
+               if bouquets is None:
+                       cnt = 0
+               else:
+                       cnt = len(bouquets)
+               if cnt > 1: # show bouquet list
+                       if withCallback:
+                               self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
+                       else:
+                               self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
+               elif cnt == 1: 
+                       self.openBouquetEPG(bouquets[0][1], withCallback)
+
+       def openSingleServiceEPG(self):
+               ref=self.session.nav.getCurrentlyPlayingServiceReference()
                ptr=eEPGCache.getInstance()
-               if ptr.startTimeQuery(ref) != -1:
-                       self.session.open(EPGSelection, ref)
-               else: # try to show now/next
-                       print 'no epg for service', ref.toString()
-                       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)
+               self.session.openWithCallback(self.closed, EPGSelection, ref)
+
+       def openEventView(self):
+               self.epglist = [ ]
+               service = self.session.nav.getCurrentService()
+               ref = self.session.nav.getCurrentlyPlayingServiceReference()
+               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:
+                       epg = eEPGCache.getInstance()
+                       ptr = epg.lookupEventTime(ref, -1)
+                       if ptr:
+                               self.epglist.append(ptr)
+                               ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +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
+               if len(self.epglist) > 0:
+                       self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
+               else:
+                       print "no epg for the service avail.. so we show multiepg instead of eventinfo"
+                       self.openMultiServiceEPG(False)
 
        def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
                if len(self.epglist) > 1:
@@ -456,7 +515,7 @@ class InfoBarEvent:
                self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
                self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
 
-               self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Duration)
+               self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
                self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
 
                self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
@@ -468,48 +527,64 @@ class InfoBarServiceName:
 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)
+       # ispause, isff, issm
+       SEEK_STATE_PLAY = (0, 0, 0, ">")
+       SEEK_STATE_PAUSE = (1, 0, 0, "||")
+       SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
+       SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
+       SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
+       SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
+       SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
+       SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
        
-       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_BACK_16X = (0, -16, 0, "<< 16x")
+       SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
+       SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
+       SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
        
-       SEEK_STATE_SM_HALF = (0, 0, 2, 0)
-       SEEK_STATE_SM_QUARTER = (0, 0, 4, 0)
-       SEEK_STATE_SM_EIGHTH = (0, 0, 8, 0)
+       SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
+       SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
+       SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
        
        def __init__(self):
                self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
                        {
-                               pNavigation.evSeekableStatusChanged: self.__seekableStatusChanged,
-                               pNavigation.evNewService: self.__serviceStarted
+                               iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
+                               iPlayableService.evStart: self.__serviceStarted,
+                               
+                               iPlayableService.evEOF: self.__evEOF,
+                               iPlayableService.evSOF: self.__evSOF,
                        })
-               self["SeekActions"] = HelpableActionMap(self, "InfobarSeekActions", 
+
+               class InfoBarSeekActionMap(HelpableActionMap):
+                       def __init__(self, screen, *args, **kwargs):
+                               HelpableActionMap.__init__(self, screen, *args, **kwargs)
+                               self.screen = screen
+                               
+                       def action(self, contexts, action):
+                               if action[:5] == "seek:":
+                                       time = int(action[5:])
+                                       self.screen.seekRelative(time * 90000)
+                                       return 1
+                               else:
+                                       return HelpableActionMap.action(self, contexts, action)
+
+               self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions", 
                        {
                                "pauseService": (self.pauseService, "pause"),
                                "unPauseService": (self.unPauseService, "continue"),
                                
                                "seekFwd": (self.seekFwd, "skip forward"),
-                               "seekFwdUp": (self.seekFwdUp, "skip forward"),
+                               "seekFwdDown": self.seekFwdDown,
+                               "seekFwdUp": self.seekFwdUp,
                                "seekBack": (self.seekBack, "skip backward"),
-                               "seekBackUp": (self.seekBackUp, "skip backward"),
+                               "seekBackDown": self.seekBackDown,
+                               "seekBackUp": self.seekBackUp,
                        }, prio=-1)
                        # give them a little more priority to win over color buttons
 
                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.onClose.append(self.delTimer)
                
                self.fwdtimer = False
                self.fwdKeyTimer = eTimer()
@@ -518,6 +593,10 @@ class InfoBarSeek:
                self.rwdtimer = False
                self.rwdKeyTimer = eTimer()
                self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
+               
+               self.onPlayStateChanged = [ ]
+               
+               self.lockedBecauseOfSkipping = False
        
        def up(self):
                pass
@@ -525,29 +604,26 @@ class InfoBarSeek:
        def down(self):
                pass
        
-       def delSeekTimer(self):
-               del self.seekTimer
+       def delTimer(self):
                del self.fwdKeyTimer
                del self.rwdKeyTimer
        
-       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 isSeekable(self):
+       def getSeek(self):
                service = self.session.nav.getCurrentService()
                if service is None:
                        return False
-               if service.seek() is None:
+
+               seek = service.seek()
+
+               if seek is None or not seek.isCurrentlySeekable():
+                       return None
+               
+               return seek
+       
+       def isSeekable(self):
+               if self.getSeek() is None:
                        return False
-               else:
-                       return True
+               return True
 
        def __seekableStatusChanged(self):
                print "seekable status changed!"
@@ -564,12 +640,11 @@ class InfoBarSeek:
 
        def setSeekState(self, state):
                service = self.session.nav.getCurrentService()
-               self.seekTimer.stop()
                
                if service is None:
                        return False
                
-               if service.seek() is None:
+               if not self.isSeekable():
                        if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
                                state = self.SEEK_STATE_PLAY
                
@@ -582,35 +657,17 @@ class InfoBarSeek:
                oldstate = self.seekstate
                self.seekstate = state
                
-               for i in range(4):
+               for i in range(3):
                        if oldstate[i] != self.seekstate[i]:
-                               (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion, self.setSkipMode)[i](self.seekstate[i])
+                               (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
 
-               return True
-               
-       def setSkipMode(self, skipmode):
-               print "setskipmode", skipmode
-               self.skipmode = skipmode
-               if skipmode == 0:
-                       self.seekTimer.stop()
-               else:
-                       self.seekTimer.start(500)
+               for c in self.onPlayStateChanged:
+                       c(self.seekstate)
                
-               service = self.session.nav.getCurrentService()
-               if service is None:
-                       return
-               
-               seekable = service.seek()
-               if seekable is None:
-                       return
+               self.checkSkipShowHideLock()
 
-               if skipmode:
-                       seekable.setTrickmode(1)
-               else:
-                       seekable.setTrickmode(0)
+               return True
                
-               self.seekbase = seekable.getPlayPosition()[1] / 90
-       
        def pauseService(self):
                if self.seekstate == self.SEEK_STATE_PAUSE:
                        print "pause, but in fact unpause"
@@ -633,70 +690,81 @@ class InfoBarSeek:
                if service is None:
                        return
                
-               seekable = service.seek()
+               seekable = self.getSeek()
                if seekable is None:
                        return
+               
                seekable.seekTo(90 * seektime)
 
-       def seekFwd(self):
+       def seekFwdDown(self):
                print "start fwd timer"
                self.fwdtimer = True
-               self.fwdKeyTimer.start(500)
+               self.fwdKeyTimer.start(1000)
 
-       def seekBack(self):
+       def seekBackDown(self):
                print "start rewind timer"
                self.rwdtimer = True
-               self.rwdKeyTimer.start(500)
+               self.rwdKeyTimer.start(1000)
 
        def seekFwdUp(self):
                print "seekFwdUp"
                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]);
+                       self.seekFwd()
+
+       def seekFwd(self):
+               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_16X: self.SEEK_STATE_PLAY,
+                               self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
+                               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):
                print "seekBackUp"
                if self.rwdtimer:
                        self.rwdKeyTimer.stop()
                        self.rwdtimer = False
+                       self.seekBack()
                
-                       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 seekBack(self):
+               lookup = {
+                               self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
+                               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_16X: 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])
                
+               if self.seekstate == self.SEEK_STATE_PAUSE:
+                       seekable = self.getSeek()
+                       if seekable is not None:
+                               seekable.seekRelative(-1, 3)
+
        def fwdTimerFire(self):
                print "Display seek fwd"
                self.fwdKeyTimer.stop()
@@ -706,13 +774,9 @@ class InfoBarSeek:
        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)
+                       seekable = self.getSeek()
+                       if seekable is not None:
+                               seekable.seekRelative(1, minutes * 60 * 90000)
        
        def rwdTimerFire(self):
                print "rwdTimerFire"
@@ -723,6 +787,58 @@ class InfoBarSeek:
        def rwdSeekTo(self, minutes):
                print "rwdSeekTo"
                self.fwdSeekTo(0 - minutes)
+       
+       def checkSkipShowHideLock(self):
+               wantlock = self.seekstate != self.SEEK_STATE_PLAY
+               
+               if self.lockedBecauseOfSkipping and not wantlock:
+                       self.unlockShow()
+                       self.lockedBecauseOfSkipping = False
+               
+               if wantlock and not self.lockedBecauseOfSkipping:
+                       self.lockShow()
+                       self.lockedBecauseOfSkipping = True
+
+       def __evEOF(self):
+               if self.seekstate != self.SEEK_STATE_PLAY:
+                       self.setSeekState(self.SEEK_STATE_PAUSE)
+                       # HACK
+                       #self.getSeek().seekRelative(1, -90000)
+                       self.setSeekState(self.SEEK_STATE_PLAY)
+               else:
+                       self.setSeekState(self.SEEK_STATE_PAUSE)
+       
+       def __evSOF(self):
+               self.setSeekState(self.SEEK_STATE_PLAY)
+               self.doSeek(0)
+
+       def seekRelative(self, diff):
+               seekable = self.getSeek()
+               if seekable is not None:
+                       seekable.seekRelative(1, diff)
+
+from Screens.PVRState import PVRState, TimeshiftState
+
+class InfoBarPVRState:
+       def __init__(self, screen=PVRState):
+               self.onPlayStateChanged.append(self.__playStateChanged)
+               self.pvrStateDialog = self.session.instantiateDialog(screen)
+               self.onShow.append(self.__mayShow)
+               self.onHide.append(self.pvrStateDialog.hide)
+       
+       def __mayShow(self):
+               if self.seekstate != self.SEEK_STATE_PLAY:
+                       self.pvrStateDialog.show()
+
+       def __playStateChanged(self, state):
+               playstateString = state[3]
+               self.pvrStateDialog["state"].setText(playstateString)
+               self.__mayShow()
+
+class InfoBarTimeshiftState(InfoBarPVRState):
+       def __init__(self):
+               InfoBarPVRState.__init__(self, screen=TimeshiftState)
+
 
 class InfoBarShowMovies:
 
@@ -776,7 +892,7 @@ class InfoBarTimeshift:
                        {
                                "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
                                "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause  # something like "backward key"
-                       })
+                       }, prio=-1) # priority over record
 
                self.timeshift_enabled = 0
                self.timeshift_state = 0
@@ -785,7 +901,8 @@ class InfoBarTimeshift:
 
                self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
                        {
-                               pNavigation.evSeekableStatusChanged: self.__seekableStatusChanged
+                               iPlayableService.evStart: self.__serviceStarted,
+                               iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
                        })
        
        def getTimeshift(self):
@@ -793,9 +910,6 @@ class InfoBarTimeshift:
                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:
@@ -807,7 +921,9 @@ class InfoBarTimeshift:
                        print "hu, timeshift already enabled?"
                else:
                        if not ts.startTimeshift():
+                               import time
                                self.timeshift_enabled = 1
+                               self.pvrStateDialog["timeshift"].setRelative(time.time())
                                
                                # PAUSE.
                                self.setSeekState(self.SEEK_STATE_PAUSE)
@@ -818,12 +934,23 @@ class InfoBarTimeshift:
                        else:
                                print "timeshift failed"
 
-       # nyi
        def stopTimeshift(self):
+               if not self.timeshift_enabled:
+                       return
                print "disable timeshift"
                ts = self.getTimeshift()
                if ts is None:
                        return
+               self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
+
+       def stopTimeshiftConfirmed(self, confirmed):
+               if not confirmed:
+                       return
+
+               ts = self.getTimeshift()
+               if ts is None:
+                       return
+
                ts.stopTimeshift()
                self.timeshift_enabled = 0
 
@@ -843,6 +970,7 @@ class InfoBarTimeshift:
                else:
                        self.setSeekState(self.SEEK_STATE_PLAY)
                        ts.activateTimeshift()
+                       self.seekRelative(0)
        
        # same as activateTimeshiftEnd, but pauses afterwards.
        def activateTimeshiftEndAndPause(self):
@@ -876,6 +1004,10 @@ class InfoBarTimeshift:
                print "timeshift activate:", enabled
                self["TimeshiftActivateActions"].setEnabled(enabled)
 
+       def __serviceStarted(self):
+               self.timeshift_enabled = False
+               self.__seekableStatusChanged()
+
 from RecordTimer import parseEvent
 
 class InfoBarInstantRecord:
@@ -887,45 +1019,49 @@ class InfoBarInstantRecord:
                                "instantRecord": (self.instantRecord, "Instant Record..."),
                        })
                self.recording = None
-               
                self["BlinkingPoint"] = BlinkingPixmapConditional()
-               self.onShown.append(self["BlinkingPoint"].hideWidget)
+               self["BlinkingPoint"].hide()
                self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
-               
+
        def stopCurrentRecording(self): 
                self.session.nav.RecordTimer.removeEntry(self.recording)
                self.recording = None
-                       
-       def startInstantRecording(self):
+
+       def startInstantRecording(self, limitEvent = False):
                serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
                
                # try to get event info
                event = None
                try:
                        service = self.session.nav.getCurrentService()
-                       info = service.info()
-                       ev = info.getEvent(0)
-                       event = ev
+                       epg = eEPGCache.getInstance()
+                       event = epg.lookupEventTime(serviceref, -1, 0)
+                       if event is None:
+                               info = service.info()
+                               ev = info.getEvent(0)
+                               event = ev
                except:
                        pass
+
+               begin = time.time()
+               end = time.time() + 3600 * 10
+               name = "instant record"
+               description = ""
+               eventid = None
                
                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])
+                       curEvent = parseEvent(event)
+                       name = curEvent[2]
+                       description = curEvent[3]
+                       eventid = curEvent[4]
+                       if limitEvent:
+                               end = curEvent[1]
                else:
-                       data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
+                       if limitEvent:
+                               self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
+                               
+               data = (begin, end, name, description, eventid)
                
-               # fix me, description. 
                self.recording = self.session.nav.recordWithTimer(serviceref, *data)
                self.recording.dontSave = True
                
@@ -938,13 +1074,28 @@ class InfoBarInstantRecord:
                return False
 
        def recordQuestionCallback(self, answer):
-               if answer == False:
+               if answer is None or answer[1] == "no":
                        return
                
                if self.isInstantRecordRunning():
-                       self.stopCurrentRecording()
+                       if answer[1] == "manualduration":
+                               self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)                             
+                       else:
+                               self.stopCurrentRecording()
                else:
-                       self.startInstantRecording()
+                       limitEvent = False
+                       if answer[1] == "event":
+                               limitEvent = True
+                       if answer[1] == "manualduration":
+                               self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
+                       self.startInstantRecording(limitEvent = limitEvent)
+
+       def inputCallback(self, value):
+               if value is not None:
+                       print "stopping recording after", int(value), "minutes."
+                       if self.recording is not None:
+                               self.recording.end = time.time() + 60 * int(value)
+                               self.session.nav.RecordTimer.timeChanged(self.recording)
 
        def instantRecord(self):
                try:
@@ -954,9 +1105,11 @@ class InfoBarInstantRecord:
                        return
        
                if self.isInstantRecordRunning():
-                       self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
+                       self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("A recording is currently running.\nWhat do you want to do?"), list=[(_("stop recording"), "yes"), (_("enter recording duration"), "manualduration"), (_("do nothing"), "no")])
+#                      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, ChoiceBox, title=_("Start recording?"), list=[(_("record indefinitely"), "indefinitely"), (_("stop after current event"), "event"), (_("enter recording duration"), "manualduration"),(_("don't record"), "no")])
+                       #self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
 
 from Screens.AudioSelection import AudioSelection
 
@@ -1002,28 +1155,36 @@ class InfoBarAdditionalInfo:
                
                self["ButtonRed"] = PixmapConditional(withTimer = False)
                self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
-               self.onShown.append(self["ButtonRed"].update)
+               self.onLayoutFinish.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.onLayoutFinish.append(self["ButtonRedText"].update)
 
                self["ButtonGreen"] = Pixmap()
                self["ButtonGreenText"] = Label(_("Subservices"))
 
                self["ButtonYellow"] = PixmapConditional(withTimer = False)
-               self["ButtonYellow"].setConnect(lambda: False)
+               self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
+               self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
+               self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
+               self.onLayoutFinish.append(self["ButtonYellow"].update)
+               self.onLayoutFinish.append(self["ButtonYellowText"].update)
 
                self["ButtonBlue"] = PixmapConditional(withTimer = False)
                self["ButtonBlue"].setConnect(lambda: False)
+               self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
+               self["ButtonBlueText"].setConnect(lambda: False)
+               self.onLayoutFinish.append(self["ButtonBlue"].update)
+               self.onLayoutFinish.append(self["ButtonBlueText"].update)
 
                self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
 
        def hideSubServiceIndication(self):
-               self["ButtonGreen"].hideWidget()
+               self["ButtonGreen"].hide()
                self["ButtonGreenText"].hide()
 
        def showSubServiceIndication(self):
-               self["ButtonGreen"].showWidget()
+               self["ButtonGreen"].show()
                self["ButtonGreenText"].show()
 
        def checkFormat(self, service):
@@ -1031,9 +1192,9 @@ class InfoBarAdditionalInfo:
                if info is not None:
                        aspect = info.getInfo(iServiceInformation.sAspect)
                        if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
-                               self["FormatActive"].showWidget()
+                               self["FormatActive"].show()
                        else:
-                               self["FormatActive"].hideWidget()
+                               self["FormatActive"].hide()
 
        def checkSubservices(self, service):
                if service.subServices().getNumberOfSubservices() > 0:
@@ -1054,31 +1215,31 @@ class InfoBarAdditionalInfo:
                                        dolby = True
                                        break
                if dolby:
-                       self["DolbyActive"].showWidget()
+                       self["DolbyActive"].show()
                else:
-                       self["DolbyActive"].hideWidget()
+                       self["DolbyActive"].hide()
 
        def checkCrypted(self, service):
                info = service.info()
                if info is not None:
                        if info.getInfo(iServiceInformation.sIsCrypted) > 0:
-                               self["CryptActive"].showWidget()
+                               self["CryptActive"].show()
                        else:
-                               self["CryptActive"].hideWidget()
+                               self["CryptActive"].hide()
 
        def gotServiceEvent(self, ev):
                service = self.session.nav.getCurrentService()
-               if ev == pNavigation.evUpdatedEventInfo:
+               if ev == iPlayableService.evUpdatedEventInfo:
                        self.checkSubservices(service)
                        self.checkFormat(service)
-               elif ev == pNavigation.evUpdatedInfo:
+               elif ev == iPlayableService.evUpdatedInfo:
                        self.checkCrypted(service)
                        self.checkDolby(service)
-               elif ev == pNavigation.evStopService:
+               elif ev == iPlayableService.evEnd:
                        self.hideSubServiceIndication()
-                       self["CryptActive"].hideWidget()
-                       self["DolbyActive"].hideWidget()
-                       self["FormatActive"].hideWidget()
+                       self["CryptActive"].hide()
+                       self["DolbyActive"].hide()
+                       self["FormatActive"].hide()
 
 class InfoBarNotifications:
        def __init__(self):
@@ -1104,7 +1265,7 @@ class InfoBarServiceNotifications:
        def __init__(self):
                self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
                        {
-                               pNavigation.evEnd: self.serviceHasEnded
+                               iPlayableService.evEnd: self.serviceHasEnded
                        })
 
        def serviceHasEnded(self):
@@ -1114,3 +1275,142 @@ class InfoBarServiceNotifications:
                        self.setSeekState(self.SEEK_STATE_PLAY)
                except:
                        pass
+
+class InfoBarCueSheetSupport:
+       CUT_TYPE_IN = 0
+       CUT_TYPE_OUT = 1
+       CUT_TYPE_MARK = 2
+       
+       def __init__(self):
+               self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions", 
+                       {
+                               "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
+                               "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
+                               "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
+                       }, prio=1) 
+               
+               self.cut_list = [ ]
+               self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+                       {
+                               iPlayableService.evStart: self.__serviceStarted,
+                       })
+
+       def __serviceStarted(self):
+               print "new service started! trying to download cuts!"
+               self.downloadCuesheet()
+
+       def __getSeekable(self):
+               service = self.session.nav.getCurrentService()
+               if service is None:
+                       return None
+               return service.seek()
+
+       def cueGetCurrentPosition(self):
+               seek = self.__getSeekable()
+               if seek is None:
+                       return None
+               r = seek.getPlayPosition()
+               if r[0]:
+                       return None
+               return long(r[1])
+
+       def jumpPreviousNextMark(self, cmp, alternative=None):
+               current_pos = self.cueGetCurrentPosition()
+               if current_pos is None:
+                       return
+               mark = self.getNearestCutPoint(current_pos, cmp=cmp)
+               if mark is not None:
+                       pts = mark[0]
+               elif alternative is not None:
+                       pts = alternative
+               else:
+                       return
+
+               seekable = self.__getSeekable()
+               if seekable is not None:
+                       seekable.seekTo(pts)
+
+       def jumpPreviousMark(self):
+               # we add 2 seconds, so if the play position is <2s after
+               # the mark, the mark before will be used
+               self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
+
+       def jumpNextMark(self):
+               self.jumpPreviousNextMark(lambda x: x)
+
+       def getNearestCutPoint(self, pts, cmp=abs):
+               # can be optimized
+               nearest = None
+               for cp in self.cut_list:
+                       diff = cmp(cp[0] - pts)
+                       if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
+                               nearest = cp
+               return nearest
+
+       def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
+               current_pos = self.cueGetCurrentPosition()
+               if current_pos is None:
+                       print "not seekable"
+                       return
+               
+               nearest_cutpoint = self.getNearestCutPoint(current_pos)
+               
+               if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
+                       if onlyreturn:
+                               return nearest_cutpoint
+                       if not onlyadd:
+                               self.removeMark(nearest_cutpoint)
+               elif not onlyremove and not onlyreturn:
+                       self.addMark((current_pos, self.CUT_TYPE_MARK))
+               
+               if onlyreturn:
+                       return None
+
+       def addMark(self, point):
+               bisect.insort(self.cut_list, point)
+               self.uploadCuesheet()
+
+       def removeMark(self, point):
+               self.cut_list.remove(point)
+               self.uploadCuesheet()
+
+       def __getCuesheet(self):
+               service = self.session.nav.getCurrentService()
+               if service is None:
+                       return None
+               return service.cueSheet()
+
+       def uploadCuesheet(self):
+               cue = self.__getCuesheet()
+
+               if cue is None:
+                       print "upload failed, no cuesheet interface"
+                       return
+               cue.setCutList(self.cut_list)
+
+       def downloadCuesheet(self):
+               cue = self.__getCuesheet()
+
+               if cue is None:
+                       print "upload failed, no cuesheet interface"
+                       return
+               self.cut_list = cue.getCutList()
+
+class InfoBarSummary(Screen):
+       skin = """
+       <screen position="0,0" size="132,64">
+               <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
+               <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
+       </screen>"""
+
+       def __init__(self, session, parent):
+               Screen.__init__(self, session)
+               self["CurrentService"] = ServiceName(self.session.nav)
+               self["Clock"] = Clock()
+
+class InfoBarSummarySupport:
+       def __init__(self):
+               pass
+       
+       def createSummary(self):
+               return InfoBarSummary