from Components.Pixmap import Pixmap, PixmapConditional
from Components.BlinkingPixmap import BlinkingPixmapConditional
from Components.ServiceName import ServiceName
-from Components.EventInfo import EventInfo
+from Components.EventInfo import EventInfo, EventInfoProgress
from ServiceReference import ServiceReference
from EpgSelection import EPGSelection
from Screens.MessageBox import MessageBox
-from Screens.Volume import Volume
-from Screens.Mute import Mute
from Screens.Dish import Dish
from Screens.Standby import Standby
from Screens.EventView import EventView
from Screens.MinuteInput import MinuteInput
from Components.Harddisk import harddiskmanager
+from Components.ServiceEventTracker import ServiceEventTracker
+
from Tools import Notifications
from Tools.Directories import *
# hack alert!
from Menu import MainMenu, mdom
-class InfoBarVolumeControl:
- """Volume control, handles volUp, volDown, volMute actions and display
- a corresponding dialog"""
- def __init__(self):
- config.audio = ConfigSubsection()
- config.audio.volume = configElement("config.audio.volume", configSequence, [100], configsequencearg.get("INTEGER", (0, 100)))
-
- self["VolumeActions"] = ActionMap( ["InfobarVolumeActions"] ,
- {
- "volumeUp": self.volUp,
- "volumeDown": self.volDown,
- "volumeMute": self.volMute,
- })
-
- self.volumeDialog = self.session.instantiateDialog(Volume)
- self.muteDialog = self.session.instantiateDialog(Mute)
-
- self.hideVolTimer = eTimer()
- self.hideVolTimer.timeout.get().append(self.volHide)
-
- vol = config.audio.volume.value[0]
- self.volumeDialog.setValue(vol)
- eDVBVolumecontrol.getInstance().setVolume(vol, vol)
-
- def volSave(self):
- config.audio.volume.value = eDVBVolumecontrol.getInstance().getVolume()
- config.audio.volume.save()
-
- def volUp(self):
- if (eDVBVolumecontrol.getInstance().isMuted()):
- self.volMute()
- eDVBVolumecontrol.getInstance().volumeUp()
- self.volumeDialog.instance.show()
- self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
- self.volSave()
- self.hideVolTimer.start(3000, True)
-
- def volDown(self):
- if (eDVBVolumecontrol.getInstance().isMuted()):
- self.volMute()
- eDVBVolumecontrol.getInstance().volumeDown()
- self.volumeDialog.instance.show()
- self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
- self.volSave()
- self.hideVolTimer.start(3000, True)
-
- def volHide(self):
- self.volumeDialog.instance.hide()
-
- def volMute(self):
- eDVBVolumecontrol.getInstance().volumeToggleMute()
- self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
-
- if (eDVBVolumecontrol.getInstance().isMuted()):
- self.muteDialog.instance.show()
- else:
- self.muteDialog.instance.hide()
-
class InfoBarDish:
def __init__(self):
self.dishDialog = self.session.instantiateDialog(Dish)
- self.onShown.append(self.dishDialog.instance.hide)
+ self.onShown.append(self.dishDialog.instance.show)
class InfoBarShowHide:
""" InfoBar show/hide control, accepts toggleShow and hide actions, might start
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,
def keyNumberGlobal(self, number):
# print "You pressed number " + str(number)
if number == 0:
- self.session.nav.zapLast()
+ self.servicelist.recallPrevService()
self.instance.show()
self.show()
else:
bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
if not bouquet.valid(): #check end of list
break
- if ((bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory):
+ if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
continue
service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
if not service is None:
- self.session.nav.playService(service) #play service
if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
- self.servicelist.setRoot(bouquet)
+ self.servicelist.clearPath()
+ if self.servicelist.bouquet_root != bouquet:
+ self.servicelist.enterPath(self.servicelist.bouquet_root)
+ self.servicelist.enterPath(bouquet)
self.servicelist.setCurrentSelection(service) #select the service in servicelist
+ self.servicelist.zap()
class InfoBarChannelSelection:
""" ChannelSelection - handles the channelSelection dialog and the initial
self.session.open(EventView, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
except:
pass
-
+
def openSingleServiceEPG(self):
ref=self.session.nav.getCurrentlyPlayingServiceReference()
ptr=eEPGCache.getInstance()
else: # try to show now/next
print 'no epg for service', ref.toString()
-
def openBouquetEPG(self, bouquet):
ptr=eEPGCache.getInstance()
services = [ ]
self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Duration)
self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
+ self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
+
class InfoBarServiceName:
def __init__(self):
self["ServiceName"] = ServiceName(self.session.nav)
-class InfoBarPVR:
-
+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_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",
+ self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+ {
+ pNavigation.evSeekableStatusChanged: self.__seekableStatusChanged,
+ pNavigation.evNewService: self.__serviceStarted
+ })
+ self["SeekActions"] = HelpableActionMap(self, "InfobarSeekActions",
{
"pauseService": (self.pauseService, "pause"),
"unPauseService": (self.unPauseService, "continue"),
"seekFwdUp": (self.seekFwdUp, "skip forward"),
"seekBack": (self.seekBack, "skip backward"),
"seekBackUp": (self.seekBackUp, "skip backward"),
-
- "movieList": (self.showMovies, "movie list"),
- "up": (self.showMovies, "movie list"),
- "down": (self.showMovies, "movie list")
- })
+ }, prio=-1)
+ # give them a little more priority to win over color buttons
self.seekstate = self.SEEK_STATE_PLAY
self.seekTimer = eTimer()
def delSeekTimer(self):
del self.seekTimer
+ del self.fwdKeyTimer
+ del self.rwdKeyTimer
def seekTimerFired(self):
self.seekbase += self.skipmode * self.skipinterval
self.doSeek(self.seekbase)
- def setSeekState(self, state):
- oldstate = self.seekstate
-
- self.seekstate = state
+ def isSeekable(self):
+ service = self.session.nav.getCurrentService()
+ if service is None:
+ return False
+ if service.seek() is None:
+ return False
+ else:
+ return True
+
+ def __seekableStatusChanged(self):
+ print "seekable status changed!"
+ if not self.isSeekable():
+ self["SeekActions"].setEnabled(False)
+ print "not seekable, return to play"
+ self.setSeekState(self.SEEK_STATE_PLAY)
+ else:
+ self["SeekActions"].setEnabled(True)
+ print "seekable"
+ def __serviceStarted(self):
+ self.seekstate = self.SEEK_STATE_PLAY
+
+ def setSeekState(self, state):
service = self.session.nav.getCurrentService()
+ self.seekTimer.stop()
+
if service is None:
- return
+ return False
+
+ if service.seek() is None:
+ if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
+ state = self.SEEK_STATE_PLAY
pauseable = service.pause()
+
+ if pauseable is None:
+ print "not pauseable."
+ state = self.SEEK_STATE_PLAY
+
+ oldstate = self.seekstate
+ self.seekstate = state
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])
+
+ return True
def setSkipMode(self, skipmode):
+ print "setskipmode", skipmode
self.skipmode = skipmode
if skipmode == 0:
self.seekTimer.stop()
self.seekbase = seekable.getPlayPosition()[1] / 90
def pauseService(self):
- if (self.seekstate == self.SEEK_STATE_PAUSE):
+ if self.seekstate == self.SEEK_STATE_PAUSE:
+ print "pause, but in fact unpause"
self.unPauseService()
else:
+ if self.seekstate == self.SEEK_STATE_PLAY:
+ print "yes, playing."
+ else:
+ print "no", self.seekstate
+ print "pause"
self.setSeekState(self.SEEK_STATE_PAUSE);
def unPauseService(self):
+ print "unpause"
self.setSeekState(self.SEEK_STATE_PLAY);
def doSeek(self, seektime):
+ print "doseek", seektime
service = self.session.nav.getCurrentService()
if service is None:
return
self.rwdKeyTimer.start(500)
def seekFwdUp(self):
+ print "seekFwdUp"
if self.fwdtimer:
self.fwdKeyTimer.stop()
self.fwdtimer = False
self.setSeekState(lookup[self.seekstate]);
def seekBackUp(self):
+ print "seekBackUp"
if self.rwdtimer:
self.rwdKeyTimer.stop()
self.rwdtimer = False
seekable.seekRelative(1, minutes * 60 * 90000)
def rwdTimerFire(self):
+ print "rwdTimerFire"
self.rwdKeyTimer.stop()
self.rwdtimer = False
self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
def rwdSeekTo(self, minutes):
+ print "rwdSeekTo"
self.fwdSeekTo(0 - minutes)
+class InfoBarShowMovies:
+
+ # i don't really like this class.
+ # it calls a not further specified "movie list" on up/down/movieList,
+ # so this is not more than an action map
+ def __init__(self):
+ self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
+ {
+ "movieList": (self.showMovies, "movie list"),
+ "up": (self.showMovies, "movie list"),
+ "down": (self.showMovies, "movie list")
+ })
+
+# InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
+
+# Hrmf.
+#
+# Timeshift works the following way:
+# demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
+# - normal playback TUNER unused PLAY enable disable disable
+# - user presses "yellow" button. TUNER record PAUSE enable disable enable
+# - user presess pause again FILE record PLAY enable disable enable
+# - user fast forwards FILE record FF enable disable enable
+# - end of timeshift buffer reached TUNER record PLAY enable enable disable
+# - user backwards FILE record BACK # !! enable disable enable
+#
+
+# in other words:
+# - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
+# freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
+# now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
+# - the user can now PVR around
+# - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
+# the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
+# after!
+# the seek actions will be disabled, but the timeshiftActivateActions will be enabled
+# - if the user rewinds, or press pause, timeshift will be activated again
+
+# note that a timeshift can be enabled ("recording") and
+# activated (currently time-shifting).
+
+class InfoBarTimeshift:
+ def __init__(self):
+ self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
+ {
+ "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
+ "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
+ }, prio=1)
+ self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
+ {
+ "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
+ "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
+ })
+
+ self.timeshift_enabled = 0
+ self.timeshift_state = 0
+ self.ts_pause_timer = eTimer()
+ self.ts_pause_timer.timeout.get().append(self.pauseService)
+
+ self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+ {
+ pNavigation.evSeekableStatusChanged: self.__seekableStatusChanged
+ })
+
+ def getTimeshift(self):
+ service = self.session.nav.getCurrentService()
+ return service.timeshift()
+
+ def startTimeshift(self):
+ # TODO: check for harddisk! (or do this in the interface? would make
+ # more sense... for example radio could be timeshifted in memory,
+ # and the decision can't be made here)
+ print "enable timeshift"
+ ts = self.getTimeshift()
+ if ts is None:
+ self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
+ print "no ts interface"
+ return
+
+ if self.timeshift_enabled:
+ print "hu, timeshift already enabled?"
+ else:
+ if not ts.startTimeshift():
+ self.timeshift_enabled = 1
+
+ # PAUSE.
+ self.setSeekState(self.SEEK_STATE_PAUSE)
+
+ # enable the "TimeshiftEnableActions", which will override
+ # the startTimeshift actions
+ self.__seekableStatusChanged()
+ else:
+ print "timeshift failed"
+
+ # nyi
+ def stopTimeshift(self):
+ print "disable timeshift"
+ ts = self.getTimeshift()
+ if ts is None:
+ return
+ ts.stopTimeshift()
+ self.timeshift_enabled = 0
+
+ # disable actions
+ self.__seekableStatusChanged()
+
+ # activates timeshift, and seeks to (almost) the end
+ def activateTimeshiftEnd(self):
+ ts = self.getTimeshift()
+
+ if ts is None:
+ return
+
+ if ts.isTimeshiftActive():
+ print "!! activate timeshift called - but shouldn't this be a normal pause?"
+ self.pauseService()
+ else:
+ self.setSeekState(self.SEEK_STATE_PLAY)
+ ts.activateTimeshift()
+
+ # same as activateTimeshiftEnd, but pauses afterwards.
+ def activateTimeshiftEndAndPause(self):
+ state = self.seekstate
+ self.activateTimeshiftEnd()
+
+ # well, this is "andPause", but it could be pressed from pause,
+ # when pausing on the (fake-)"live" picture, so an un-pause
+ # is perfectly ok.
+
+ print "now, pauseService"
+ if state == self.SEEK_STATE_PLAY:
+ print "is PLAYING, start pause timer"
+ self.ts_pause_timer.start(200, 1)
+ else:
+ print "unpause"
+ self.unPauseService()
+
+ def __seekableStatusChanged(self):
+ enabled = False
+
+ print "self.isSeekable", self.isSeekable()
+ print "self.timeshift_enabled", self.timeshift_enabled
+
+ # when this service is not seekable, but timeshift
+ # is enabled, this means we can activate
+ # the timeshift
+ if not self.isSeekable() and self.timeshift_enabled:
+ enabled = True
+
+ print "timeshift activate:", enabled
+ self["TimeshiftActivateActions"].setEnabled(enabled)
+
from RecordTimer import parseEvent
class InfoBarInstantRecord:
if event is not None:
data = parseEvent(event)
- data = (data[0], data[1] + 3600 * 10, data[2], data[3], data[4])
+ begin = data[0]
+ if begin < time.time():
+ begin = time.time()
+
+ end = data[1]
+ if end < begin:
+ end = begin
+
+ end += 3600 * 10
+
+ data = (begin, end, data[2], data[3], data[4])
else:
data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
self.hideSubServiceIndication()
def checkDolby(self, service):
+ # FIXME
dolby = False
audio = service.audioTracks()
if audio is not None:
self.session.openWithCallback(cb, *n[1:])
else:
self.session.open(*n[1:])
+
+class InfoBarServiceNotifications:
+ def __init__(self):
+ self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+ {
+ pNavigation.evEnd: self.serviceHasEnded
+ })
+
+ def serviceHasEnded(self):
+ print "service end!"
+
+ try:
+ self.setSeekState(self.SEEK_STATE_PLAY)
+ except:
+ pass