Playback/Skipping fixes / cleanup by A. Holst
[vuplus_dvbapp] / lib / python / Screens / InfoBarGenerics.py
index a3e56a4..4bcadef 100644 (file)
@@ -26,13 +26,14 @@ from Screens.PictureInPicture import PictureInPicture
 from Screens.SubtitleDisplay import SubtitleDisplay
 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
 from Screens.TimeDateInput import TimeDateInput
+from Screens.UnhandledKey import UnhandledKey
 from ServiceReference import ServiceReference
 
 from Tools import Notifications
 from Tools.Directories import fileExists
 
 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
-       iPlayableService, eServiceReference, eEPGCache
+       iPlayableService, eServiceReference, eEPGCache, eActionMap
 
 from time import time, localtime, strftime
 from os import stat as os_stat
@@ -47,6 +48,39 @@ class InfoBarDish:
        def __init__(self):
                self.dishDialog = self.session.instantiateDialog(Dish)
 
+class InfoBarUnhandledKey:
+       def __init__(self):
+               self.unhandledKeyDialog = self.session.instantiateDialog(UnhandledKey)
+               self.hideUnhandledKeySymbolTimer = eTimer()
+               self.hideUnhandledKeySymbolTimer.callback.append(self.unhandledKeyDialog.hide)
+               self.checkUnusedTimer = eTimer()
+               self.checkUnusedTimer.callback.append(self.checkUnused)
+               self.onLayoutFinish.append(self.unhandledKeyDialog.hide)
+               eActionMap.getInstance().bindAction('', -0x7FFFFFFF, self.actionA) #highest prio
+               eActionMap.getInstance().bindAction('', 0x7FFFFFFF, self.actionB) #lowest prio
+               self.flags = (1<<1);
+               self.uflags = 0;
+
+       #this function is called on every keypress!
+       def actionA(self, key, flag):
+               if flag != 4:
+                       if self.flags & (1<<1):
+                               self.flags = self.uflags = 0
+                       self.flags |= (1<<flag)
+                       if flag == 1: # break
+                               self.checkUnusedTimer.start(0, True)
+               return 0
+
+       #this function is only called when no other action has handled this key
+       def actionB(self, key, flag):
+               if flag != 4:
+                       self.uflags |= (1<<flag)
+
+       def checkUnused(self):
+               if self.flags == self.uflags:
+                       self.unhandledKeyDialog.show()
+                       self.hideUnhandledKeySymbolTimer.start(2000, True)
+
 class InfoBarShowHide:
        """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
        fancy animations. """
@@ -453,7 +487,7 @@ class InfoBarEPG:
                self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
                        {
                                "showEventInfo": (self.openEventView, _("show EPG...")),
-                               "showEventInfoPlugin": (self.showEventInfoPlugins, _("show single service EPG...")),
+                               "showEventInfoPlugin": (self.showEventInfoPlugins, _("list of EPG views...")),
                                "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
                        })
 
@@ -682,7 +716,7 @@ class InfoBarSeek:
        SEEK_STATE_PAUSE = (1, 0, 0, "||")
        SEEK_STATE_EOF = (1, 0, 0, "END")
 
-       def __init__(self, actionmap = "InfobarSeekActions", useSeekBackHack=True):
+       def __init__(self, actionmap = "InfobarSeekActions"):
                self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
                        {
                                iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
@@ -691,6 +725,7 @@ class InfoBarSeek:
                                iPlayableService.evEOF: self.__evEOF,
                                iPlayableService.evSOF: self.__evSOF,
                        })
+               self.fast_winding_hint_message_showed = False
 
                class InfoBarSeekActionMap(HelpableActionMap):
                        def __init__(self, screen, *args, **kwargs):
@@ -738,20 +773,10 @@ class InfoBarSeek:
                self.__seekableStatusChanged()
 
        def makeStateForward(self, n):
-#              minspeed = config.seek.stepwise_minspeed.value
-#              repeat = int(config.seek.stepwise_repeat.value)
-#              if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
-#                      return (0, n * repeat, repeat, ">> %dx" % n)
-#              else:
-                       return (0, n, 0, ">> %dx" % n)
+               return (0, n, 0, ">> %dx" % n)
 
        def makeStateBackward(self, n):
-#              minspeed = config.seek.stepwise_minspeed.value
-#              repeat = int(config.seek.stepwise_repeat.value)
-#              if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
-#                      return (0, -n * repeat, repeat, "<< %dx" % n)
-#              else:
-                       return (0, -n, 0, "<< %dx" % n)
+               return (0, -n, 0, "<< %dx" % n)
 
        def makeStateSlowMotion(self, n):
                return (0, 0, n, "/%d" % n)
@@ -817,6 +842,7 @@ class InfoBarSeek:
 #                      print "seekable"
 
        def __serviceStarted(self):
+               self.fast_winding_hint_message_showed = False
                self.seekstate = self.SEEK_STATE_PLAY
                self.__seekableStatusChanged()
 
@@ -907,6 +933,13 @@ class InfoBarSeek:
                        self.showAfterSeek()
 
        def seekFwd(self):
+               seek = self.getSeek()
+               if seek and not (seek.isCurrentlySeekable() & 2):
+                       if not self.fast_winding_hint_message_showed and (seek.isCurrentlySeekable() & 1):
+                               self.session.open(MessageBox, _("No fast winding possible yet.. but you can use the number buttons to skip forward/backward!"), MessageBox.TYPE_INFO, timeout=10)
+                               self.fast_winding_hint_message_showed = True
+                               return
+                       return 0 # trade as unhandled action
                if self.seekstate == self.SEEK_STATE_PLAY:
                        self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value)))
                elif self.seekstate == self.SEEK_STATE_PAUSE:
@@ -936,6 +969,13 @@ class InfoBarSeek:
                        self.setSeekState(self.makeStateSlowMotion(speed))
 
        def seekBack(self):
+               seek = self.getSeek()
+               if seek and not (seek.isCurrentlySeekable() & 2):
+                       if not self.fast_winding_hint_message_showed and (seek.isCurrentlySeekable() & 1):
+                               self.session.open(MessageBox, _("No fast winding possible yet.. but you can use the number buttons to skip forward/backward!"), MessageBox.TYPE_INFO, timeout=10)
+                               self.fast_winding_hint_message_showed = True
+                               return
+                       return 0 # trade as unhandled action
                seekstate = self.seekstate
                if seekstate == self.SEEK_STATE_PLAY:
                        self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
@@ -1060,15 +1100,21 @@ class InfoBarPVRState:
                        self.pvrStateDialog.hide()
                else:
                        self._mayShow()
-                       
 
 class InfoBarTimeshiftState(InfoBarPVRState):
        def __init__(self):
                InfoBarPVRState.__init__(self, screen=TimeshiftState, force_show = True)
+               self.__hideTimer = eTimer()
+               self.__hideTimer.callback.append(self.__hideTimeshiftState)
 
        def _mayShow(self):
-               if self.execing and self.timeshift_enabled and self.seekstate != self.SEEK_STATE_PLAY:
+               if self.execing and self.timeshift_enabled:
                        self.pvrStateDialog.show()
+                       if self.seekstate == self.SEEK_STATE_PLAY and not self.shown:
+                               self.__hideTimer.start(5*1000, True)
+
+       def __hideTimeshiftState(self):
+               self.pvrStateDialog.hide()
 
 class InfoBarShowMovies:
 
@@ -1964,8 +2010,10 @@ class InfoBarCueSheetSupport:
 
                        if last is not None:
                                self.resume_point = last
+                               
+                               l = last / 90000
                                if config.usage.on_movie_start.value == "ask":
-                                       Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
+                                       Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?") + "\n" + (_("Resume position at %s") % ("%d:%02d:%02d" % (l/3600, l%3600/60, l%60))), timeout=10)
                                elif config.usage.on_movie_start.value == "resume":
 # TRANSLATORS: The string "Resuming playback" flashes for a moment
 # TRANSLATORS: at the start of a movie, when the user has selected
@@ -2026,20 +2074,21 @@ class InfoBarCueSheetSupport:
                return True
 
        def jumpPreviousMark(self):
-               # we add 2 seconds, so if the play position is <2s after
+               # we add 5 seconds, so if the play position is <5s after
                # the mark, the mark before will be used
                self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True)
 
        def jumpNextMark(self):
-               if not self.jumpPreviousNextMark(lambda x: x):
+               if not self.jumpPreviousNextMark(lambda x: x-90000):
                        self.doSeek(-1)
 
        def getNearestCutPoint(self, pts, cmp=abs, start=False):
                # can be optimized
-               beforecut = False
+               beforecut = True
                nearest = None
+               bestdiff = -1
+               instate = True
                if start:
-                       beforecut = True
                        bestdiff = cmp(0 - pts)
                        if bestdiff >= 0:
                                nearest = [0, False]
@@ -2048,14 +2097,19 @@ class InfoBarCueSheetSupport:
                                beforecut = False
                                if cp[1] == self.CUT_TYPE_IN:  # Start is here, disregard previous marks
                                        diff = cmp(cp[0] - pts)
-                                       if diff >= 0:
+                                       if start and diff >= 0:
                                                nearest = cp
                                                bestdiff = diff
                                        else:
                                                nearest = None
-                       if cp[1] in (self.CUT_TYPE_MARK, self.CUT_TYPE_LAST):
+                                               bestdiff = -1
+                       if cp[1] == self.CUT_TYPE_IN:
+                               instate = True
+                       elif cp[1] == self.CUT_TYPE_OUT:
+                               instate = False
+                       elif cp[1] in (self.CUT_TYPE_MARK, self.CUT_TYPE_LAST):
                                diff = cmp(cp[0] - pts)
-                               if diff >= 0 and (nearest is None or bestdiff > diff):
+                               if instate and diff >= 0 and (nearest is None or bestdiff > diff):
                                        nearest = cp
                                        bestdiff = diff
                return nearest