skipping: skip relative to first position
[enigma2.git] / lib / python / Screens / InfoBarGenerics.py
index 978a113443590b2a30e034d33dd00629d8556e3c..4f1cd99c5c26f5a4e1b1d80d68a55a827df0757e 100644 (file)
@@ -1,7 +1,8 @@
 from Screen import Screen
 from Components.ActionMap import ActionMap, HelpableActionMap
 from Components.ActionMap import NumberActionMap
 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 Components.config import configfile, configsequencearg
 from Components.config import config, configElement, ConfigSubsection, configSequence
 from ChannelSelection import ChannelSelection
@@ -17,8 +18,12 @@ from EpgSelection import EPGSelection
 from Screens.MessageBox import MessageBox
 from Screens.Volume import Volume
 from Screens.Mute import Mute
 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.Standby import Standby
 from Screens.EventView import EventView
+from Components.Harddisk import harddiskmanager
+
+from Tools import Notifications
 
 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
 from enigma import *
 
 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
 from enigma import *
@@ -34,7 +39,7 @@ class InfoBarVolumeControl:
        a corresponding dialog"""
        def __init__(self):
                config.audio = ConfigSubsection()
        a corresponding dialog"""
        def __init__(self):
                config.audio = ConfigSubsection()
-               config.audio.volume = configElement("config.audio.volume", configSequence, [5], configsequencearg.get("INTEGER", (0, 100)))
+               config.audio.volume = configElement("config.audio.volume", configSequence, [100], configsequencearg.get("INTEGER", (0, 100)))
 
                self["VolumeActions"] = ActionMap( ["InfobarVolumeActions"] ,
                        {
 
                self["VolumeActions"] = ActionMap( ["InfobarVolumeActions"] ,
                        {
@@ -64,7 +69,7 @@ class InfoBarVolumeControl:
                self.volumeDialog.instance.show()
                self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
                self.volSave()
                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()):
 
        def     volDown(self):
                if (eDVBVolumecontrol.getInstance().isMuted()):
@@ -73,7 +78,7 @@ class InfoBarVolumeControl:
                self.volumeDialog.instance.show()
                self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
                self.volSave()
                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()
                
        def volHide(self):
                self.volumeDialog.instance.hide()
@@ -87,6 +92,11 @@ class InfoBarVolumeControl:
                else:
                        self.muteDialog.instance.hide()
 
                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. """
 class InfoBarShowHide:
        """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
        fancy animations. """
@@ -109,7 +119,7 @@ class InfoBarShowHide:
                
                self.hideTimer = eTimer()
                self.hideTimer.timeout.get().append(self.doTimerHide)
                
                self.hideTimer = eTimer()
                self.hideTimer.timeout.get().append(self.doTimerHide)
-               self.hideTimer.start(5000)
+               self.hideTimer.start(5000, True)
 
        def delHideTimer(self):
                del self.hideTimer
 
        def delHideTimer(self):
                del self.hideTimer
@@ -119,8 +129,7 @@ class InfoBarShowHide:
                
        def show(self):
                self.state = self.STATE_SHOWN
                
        def show(self):
                self.state = self.STATE_SHOWN
-               self.hideTimer.stop()
-               self.hideTimer.start(5000)
+               self.hideTimer.start(5000, True)
 
        def doTimerHide(self):
                self.hideTimer.stop()
 
        def doTimerHide(self):
                self.hideTimer.stop()
@@ -157,7 +166,7 @@ class NumberZap(Screen):
                self.close(int(self["number"].getText()))
 
        def keyNumberGlobal(self, number):
                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:
                self.field = self.field + str(number)
                self["number"].setText(self.field)
                if len(self.field) >= 4:
@@ -189,7 +198,7 @@ class NumberZap(Screen):
 
                self.Timer = eTimer()
                self.Timer.timeout.get().append(self.keyOK)
 
                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"""
 
 class InfoBarPowerKey:
        """ PowerKey stuff - handles the powerkey press and powerkey release actions"""
@@ -211,7 +220,7 @@ class InfoBarPowerKey:
        
        def powerdown(self):
                self.standbyblocked = 0
        
        def powerdown(self):
                self.standbyblocked = 0
-               self.powerKeyTimer.start(3000)
+               self.powerKeyTimer.start(3000, True)
 
        def powerup(self):
                self.powerKeyTimer.stop()
 
        def powerup(self):
                self.powerKeyTimer.stop()
@@ -374,6 +383,50 @@ class InfoBarEPG:
                        self.epglist[1]=tmp
                        setEvent(self.epglist[0])
 
                        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):
 class InfoBarEvent:
        """provides a current/next event info display"""
        def __init__(self):
@@ -391,6 +444,26 @@ class InfoBarServiceName:
                self["ServiceName"] = ServiceName(self.session.nav)
 
 class InfoBarPVR:
                self["ServiceName"] = ServiceName(self.session.nav)
 
 class InfoBarPVR:
+
+       # 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, 0, 0, 32)
+       SEEK_STATE_FF_64X = (0, 0, 0, 64)
+       SEEK_STATE_FF_128X = (0, 0, 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)
+       
        """handles PVR specific actions like seeking, pause"""
        def __init__(self):
                self["PVRActions"] = HelpableActionMap(self, "InfobarPVRActions", 
        """handles PVR specific actions like seeking, pause"""
        def __init__(self):
                self["PVRActions"] = HelpableActionMap(self, "InfobarPVRActions", 
@@ -401,14 +474,70 @@ class InfoBarPVR:
                                "seekFwd": (self.seekFwd, "skip forward"),
                                "seekBack": (self.seekBack, "skip backward"),
                        })
                                "seekFwd": (self.seekFwd, "skip forward"),
                                "seekBack": (self.seekBack, "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)
+       
+       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):
        def pauseService(self):
-               self.session.nav.pause(1)
+               self.setSeekState(self.SEEK_STATE_PAUSE);
                
        def unPauseService(self):
                
        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
                service = self.session.nav.getCurrentService()
                if service is None:
                        return
@@ -416,13 +545,49 @@ class InfoBarPVR:
                seekable = service.seek()
                if seekable is None:
                        return
                seekable = service.seek()
                if seekable is None:
                        return
-               seekable.seekRelative(dir, 90 * seektime)
+               seekable.seekTo(90 * seektime)
 
        def seekFwd(self):
 
        def seekFwd(self):
-               self.doSeek(+1, 60000)
+               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 seekBack(self):
        
        def seekBack(self):
-               self.doSeek(-1, 60000)
+               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]);
+
+from RecordTimer import parseEvent
 
 class InfoBarInstantRecord:
        """Instant Record - handles the instantRecord action in order to 
 
 class InfoBarInstantRecord:
        """Instant Record - handles the instantRecord action in order to 
@@ -435,7 +600,7 @@ class InfoBarInstantRecord:
                self.recording = None
                
                self["BlinkingPoint"] = BlinkingPixmapConditional()
                self.recording = None
                
                self["BlinkingPoint"] = BlinkingPixmapConditional()
-               self.onShown.append(self["BlinkingPoint"].hidePixmap)
+               self.onShown.append(self["BlinkingPoint"].hideWidget)
                self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
                
        def stopCurrentRecording(self): 
                self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
                
        def stopCurrentRecording(self): 
@@ -444,19 +609,25 @@ class InfoBarInstantRecord:
                        
        def startInstantRecording(self):
                serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
                        
        def startInstantRecording(self):
                serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
-                       
+               
                # try to get event info
                # try to get event info
-               epg = None
+               event = None
                try:
                        service = self.session.nav.getCurrentService()
                        info = service.info()
                        ev = info.getEvent(0)
                try:
                        service = self.session.nav.getCurrentService()
                        info = service.info()
                        ev = info.getEvent(0)
-                       epg = ev
+                       event = ev
                except:
                        pass
                
                except:
                        pass
                
+               if event is not None:
+                       data = parseEvent(event)
+                       data = (data[0], data[1] + 3600 * 10, data[2], data[3], data[4])
+               else:
+                       data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
+               
                # fix me, description. 
                # 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())
                self.recording.dontSave = True
                
                #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
@@ -504,6 +675,26 @@ class InfoBarAudioSelection:
                if n > 0:
                        self.session.open(AudioSelection, audio)
 
                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"] = PixmapConditional()
 class InfoBarAdditionalInfo:
        def __init__(self):
                self["DolbyActive"] = PixmapConditional()
@@ -518,8 +709,40 @@ class InfoBarAdditionalInfo:
                # TODO: get the info from c++ somehow
                self["FormatActive"].setConnect(lambda: False)
                
                # TODO: get the info from c++ somehow
                self["FormatActive"].setConnect(lambda: False)
                
-               self["ButtonRed"] = Pixmap()
-               self["ButtonRedText"] = Label(_("Record"))
-               self["ButtonGreen"] = Pixmap()
-               self["ButtonYellow"] = Pixmap()
-               self["ButtonBlue"] = Pixmap()
\ No newline at end of file
+               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"] = PixmapConditional()
+               self["ButtonGreen"].setConnect(lambda: self.session.nav.getCurrentService().subServices().getNumberOfSubservices() > 0)
+               self["ButtonGreenText"] = LabelConditional(text = _("Subservices"))
+               self["ButtonGreenText"].setConnect(lambda: self.session.nav.getCurrentService().subServices().getNumberOfSubservices() > 0)
+
+               self["ButtonYellow"] = PixmapConditional()
+               self["ButtonYellow"].setConnect(lambda: False)
+
+               self["ButtonBlue"] = PixmapConditional()
+               self["ButtonBlue"].setConnect(lambda: False)
+
+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:])