1 from Screen import Screen
2 from Components.ActionMap import ActionMap, HelpableActionMap
3 from Components.ActionMap import NumberActionMap
4 from Components.Label import *
5 from Components.ProgressBar import *
6 from Components.config import configfile, configsequencearg
7 from Components.config import config, configElement, ConfigSubsection, configSequence
8 from ChannelSelection import ChannelSelection
10 from Components.Pixmap import Pixmap, PixmapConditional
11 from Components.BlinkingPixmap import BlinkingPixmapConditional
12 from Components.ServiceName import ServiceName
13 from Components.EventInfo import EventInfo
15 from ServiceReference import ServiceReference
16 from EpgSelection import EPGSelection
18 from Screens.MessageBox import MessageBox
19 from Screens.Volume import Volume
20 from Screens.Mute import Mute
21 from Screens.Dish import Dish
22 from Screens.Standby import Standby
23 from Screens.EventView import EventView
24 from Components.Harddisk import harddiskmanager
26 from Tools import Notifications
28 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
35 from Menu import MainMenu, mdom
37 class InfoBarVolumeControl:
38 """Volume control, handles volUp, volDown, volMute actions and display
39 a corresponding dialog"""
41 config.audio = ConfigSubsection()
42 config.audio.volume = configElement("config.audio.volume", configSequence, [5], configsequencearg.get("INTEGER", (0, 100)))
44 self["VolumeActions"] = ActionMap( ["InfobarVolumeActions"] ,
46 "volumeUp": self.volUp,
47 "volumeDown": self.volDown,
48 "volumeMute": self.volMute,
51 self.volumeDialog = self.session.instantiateDialog(Volume)
52 self.muteDialog = self.session.instantiateDialog(Mute)
54 self.hideVolTimer = eTimer()
55 self.hideVolTimer.timeout.get().append(self.volHide)
57 vol = config.audio.volume.value[0]
58 self.volumeDialog.setValue(vol)
59 eDVBVolumecontrol.getInstance().setVolume(vol, vol)
62 config.audio.volume.value = eDVBVolumecontrol.getInstance().getVolume()
63 config.audio.volume.save()
66 if (eDVBVolumecontrol.getInstance().isMuted()):
68 eDVBVolumecontrol.getInstance().volumeUp()
69 self.volumeDialog.instance.show()
70 self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
72 self.hideVolTimer.start(3000)
75 if (eDVBVolumecontrol.getInstance().isMuted()):
77 eDVBVolumecontrol.getInstance().volumeDown()
78 self.volumeDialog.instance.show()
79 self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
81 self.hideVolTimer.start(3000)
84 self.volumeDialog.instance.hide()
87 eDVBVolumecontrol.getInstance().volumeToggleMute()
88 self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
90 if (eDVBVolumecontrol.getInstance().isMuted()):
91 self.muteDialog.instance.show()
93 self.muteDialog.instance.hide()
97 self.dishDialog = self.session.instantiateDialog(Dish)
98 self.onShown.append(self.dishDialog.instance.hide)
100 class InfoBarShowHide:
101 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
102 fancy animations. """
109 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
111 "toggleShow": self.toggleShow,
115 self.state = self.STATE_SHOWN
117 self.onExecBegin.append(self.show)
118 self.onClose.append(self.delHideTimer)
120 self.hideTimer = eTimer()
121 self.hideTimer.timeout.get().append(self.doTimerHide)
122 self.hideTimer.start(5000)
124 def delHideTimer(self):
131 self.state = self.STATE_SHOWN
132 self.hideTimer.stop()
133 self.hideTimer.start(5000)
135 def doTimerHide(self):
136 self.hideTimer.stop()
137 if self.state == self.STATE_SHOWN:
139 self.state = self.STATE_HIDDEN
141 def toggleShow(self):
142 if self.state == self.STATE_SHOWN:
144 #pls check animation support, sorry
146 self.hideTimer.stop()
147 self.state = self.STATE_HIDDEN
148 elif self.state == self.STATE_HIDDEN:
153 self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
154 self.state = self.STATE_SHOWN
157 self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
158 self.state = self.STATE_HIDDEN
160 class NumberZap(Screen):
167 self.close(int(self["number"].getText()))
169 def keyNumberGlobal(self, number):
170 self.Timer.start(3000) #reset timer
171 self.field = self.field + str(number)
172 self["number"].setText(self.field)
173 if len(self.field) >= 4:
176 def __init__(self, session, number):
177 Screen.__init__(self, session)
178 self.field = str(number)
180 self["channel"] = Label(_("Channel:"))
182 self["number"] = Label(self.field)
184 self["actions"] = NumberActionMap( [ "SetupActions" ],
188 "1": self.keyNumberGlobal,
189 "2": self.keyNumberGlobal,
190 "3": self.keyNumberGlobal,
191 "4": self.keyNumberGlobal,
192 "5": self.keyNumberGlobal,
193 "6": self.keyNumberGlobal,
194 "7": self.keyNumberGlobal,
195 "8": self.keyNumberGlobal,
196 "9": self.keyNumberGlobal,
197 "0": self.keyNumberGlobal
200 self.Timer = eTimer()
201 self.Timer.timeout.get().append(self.keyOK)
202 self.Timer.start(3000)
204 class InfoBarPowerKey:
205 """ PowerKey stuff - handles the powerkey press and powerkey release actions"""
208 self.powerKeyTimer = eTimer()
209 self.powerKeyTimer.timeout.get().append(self.powertimer)
210 self["PowerKeyActions"] = HelpableActionMap(self, "PowerKeyActions",
212 "powerdown": self.powerdown,
213 "powerup": self.powerup,
214 "discreteStandby": (self.standby, "Go standby"),
215 "discretePowerOff": (self.quit, "Go to deep standby"),
218 def powertimer(self):
219 print "PowerOff - Now!"
223 self.standbyblocked = 0
224 self.powerKeyTimer.start(3000)
227 self.powerKeyTimer.stop()
228 if self.standbyblocked == 0:
229 self.standbyblocked = 1
233 self.session.open(Standby, self)
239 class InfoBarNumberZap:
240 """ Handles an initial number for NumberZapping """
242 self["NumberZapActions"] = NumberActionMap( [ "NumberZapActions"],
244 "1": self.keyNumberGlobal,
245 "2": self.keyNumberGlobal,
246 "3": self.keyNumberGlobal,
247 "4": self.keyNumberGlobal,
248 "5": self.keyNumberGlobal,
249 "6": self.keyNumberGlobal,
250 "7": self.keyNumberGlobal,
251 "8": self.keyNumberGlobal,
252 "9": self.keyNumberGlobal,
253 "0": self.keyNumberGlobal,
256 def keyNumberGlobal(self, number):
257 # print "You pressed number " + str(number)
258 self.session.openWithCallback(self.numberEntered, NumberZap, number)
260 def numberEntered(self, retval):
261 # print self.servicelist
263 self.zapToNumber(retval)
265 def searchNumberHelper(self, serviceHandler, num, bouquet):
266 servicelist = serviceHandler.list(bouquet)
267 if not servicelist is None:
269 serviceIterator = servicelist.getNext()
270 if not serviceIterator.valid(): #check end of list
272 if serviceIterator.flags: #assume normal dvb service have no flags set
275 if not num: #found service with searched number ?
276 return serviceIterator, 0
279 def zapToNumber(self, number):
280 bouquet = self.servicelist.bouquet_root
282 serviceHandler = eServiceCenter.getInstance()
283 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
284 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
286 bouquetlist = serviceHandler.list(bouquet)
287 if not bouquetlist is None:
289 bouquet = bouquetlist.getNext()
290 if not bouquet.valid(): #check end of list
292 if ((bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory):
294 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
295 if not service is None:
296 self.session.nav.playService(service) #play service
297 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
298 self.servicelist.setRoot(bouquet)
299 self.servicelist.setCurrentSelection(service) #select the service in servicelist
301 class InfoBarChannelSelection:
302 """ ChannelSelection - handles the channelSelection dialog and the initial
303 channelChange actions which open the channelSelection dialog """
306 self.servicelist = self.session.instantiateDialog(ChannelSelection)
308 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
310 "switchChannelUp": self.switchChannelUp,
311 "switchChannelDown": self.switchChannelDown,
312 "zapUp": (self.zapUp, _("next channel")),
313 "zapDown": (self.zapDown, _("previous channel")),
316 def switchChannelUp(self):
317 self.servicelist.moveUp()
318 self.session.execDialog(self.servicelist)
320 def switchChannelDown(self):
321 self.servicelist.moveDown()
322 self.session.execDialog(self.servicelist)
325 self.servicelist.moveUp()
326 self.servicelist.zap()
331 self.servicelist.moveDown()
332 self.servicelist.zap()
337 """ Handles a menu action, to open the (main) menu """
339 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
341 "mainMenu": (self.mainMenu, "Enter main menu..."),
345 print "loading mainmenu XML..."
346 menu = mdom.childNodes[0]
347 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
348 self.session.open(MainMenu, menu, menu.childNodes)
351 """ EPG - Opens an EPG list when the showEPGList action fires """
353 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
355 "showEPGList": (self.showEPGList, _("show EPG...")),
358 def showEPGList(self):
359 ref=self.session.nav.getCurrentlyPlayingServiceReference()
360 ptr=eEPGCache.getInstance()
361 if ptr.startTimeQuery(ref) != -1:
362 self.session.open(EPGSelection, ref)
363 else: # try to show now/next
364 print 'no epg for service', ref.toString()
367 service = self.session.nav.getCurrentService()
368 info = service.info()
371 self.epglist.append(ptr)
374 self.epglist.append(ptr)
375 if len(self.epglist) > 0:
376 self.session.open(EventView, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
380 def eventViewCallback(self, setEvent, val): #used for now/next displaying
381 if len(self.epglist) > 1:
382 tmp = self.epglist[0]
383 self.epglist[0]=self.epglist[1]
385 setEvent(self.epglist[0])
390 """provides a snr/agc/ber display"""
392 self["snr"] = Label()
393 self["agc"] = Label()
394 self["ber"] = Label()
395 self["snr_percent"] = Label()
396 self["agc_percent"] = Label()
397 self["ber_count"] = Label()
398 self["snr_progress"] = ProgressBar()
399 self["agc_progress"] = ProgressBar()
400 self["ber_progress"] = ProgressBar()
401 self.timer = eTimer()
402 self.timer.timeout.get().append(self.updateTunerInfo)
403 self.timer.start(500)
409 return (long)(log(val)/log(2))
412 def updateTunerInfo(self):
413 if self.instance.isVisible():
414 service = self.session.nav.getCurrentService()
418 if service is not None:
419 feinfo = service.frontendStatusInfo()
420 if feinfo is not None:
421 ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
422 snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
423 agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
424 self["snr_percent"].setText("%d%%"%(snr))
425 self["agc_percent"].setText("%d%%"%(agc))
426 self["ber_count"].setText("%d"%(ber))
427 self["snr_progress"].setValue(snr)
428 self["agc_progress"].setValue(agc)
429 self["ber_progress"].setValue(self.calc(ber))
432 """provides a current/next event info display"""
434 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
435 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
437 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
438 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
440 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Duration)
441 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
443 class InfoBarServiceName:
445 self["ServiceName"] = ServiceName(self.session.nav)
449 # ispause, isff, issm, skip
450 SEEK_STATE_PLAY = (0, 0, 0, 0)
451 SEEK_STATE_PAUSE = (1, 0, 0, 0)
452 SEEK_STATE_FF_2X = (0, 2, 0, 0)
453 SEEK_STATE_FF_4X = (0, 4, 0, 0)
454 SEEK_STATE_FF_8X = (0, 8, 0, 0)
455 SEEK_STATE_FF_32X = (0, 0, 0, 32)
456 SEEK_STATE_FF_64X = (0, 0, 0, 64)
458 SEEK_STATE_BACK_4X = (0, 0, 0, -4)
459 SEEK_STATE_BACK_32X = (0, 0, 0, -32)
460 SEEK_STATE_BACK_64X = (0, 0, 0, -64)
462 SEEK_STATE_SM_HALF = (0, 0, 2, 0)
463 SEEK_STATE_SM_QUARTER = (0, 0, 4, 0)
464 SEEK_STATE_SM_EIGHTH = (0, 0, 8, 0)
466 """handles PVR specific actions like seeking, pause"""
468 self["PVRActions"] = HelpableActionMap(self, "InfobarPVRActions",
470 "pauseService": (self.pauseService, "pause"),
471 "unPauseService": (self.unPauseService, "continue"),
473 "seekFwd": (self.seekFwd, "skip forward"),
474 "seekBack": (self.seekBack, "skip backward"),
477 self.seekstate = self.SEEK_STATE_PLAY
478 self.seekTimer = eTimer()
479 self.seekTimer.timeout.get().append(self.seekTimerFired)
480 self.skipinterval = 500 # 500ms skip interval
482 def seekTimerFired(self):
483 if self.skipmode > 0:
484 self.doSeek(+1, self.skipmode * self.skipinterval)
486 self.doSeek(-1, -self.skipmode * self.skipinterval)
488 def setSeekState(self, state):
489 oldstate = self.seekstate
491 self.seekstate = state
493 service = self.session.nav.getCurrentService()
497 pauseable = service.pause()
500 if oldstate[i] != self.seekstate[i]:
501 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion, self.setSkipMode)[i](self.seekstate[i])
503 def setSkipMode(self, skipmode):
504 self.skipmode = skipmode
506 self.seekTimer.stop()
508 self.seekTimer.start(500)
510 def pauseService(self):
511 self.setSeekState(self.SEEK_STATE_PAUSE);
513 def unPauseService(self):
514 self.setSeekState(self.SEEK_STATE_PLAY);
516 def doSeek(self, dir, seektime):
517 service = self.session.nav.getCurrentService()
521 seekable = service.seek()
524 seekable.seekRelative(dir, 90 * seektime)
528 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
529 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
530 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
531 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
532 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
533 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
534 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_64X,
535 self.SEEK_STATE_BACK_4X: self.SEEK_STATE_PLAY,
536 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_4X,
537 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
538 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
539 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
540 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
542 self.setSeekState(lookup[self.seekstate]);
546 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_4X,
547 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
548 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
549 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
550 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
551 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
552 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
553 self.SEEK_STATE_BACK_4X: self.SEEK_STATE_BACK_32X,
554 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
555 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_64X,
556 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
557 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
558 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
560 self.setSeekState(lookup[self.seekstate]);
562 class InfoBarInstantRecord:
563 """Instant Record - handles the instantRecord action in order to
564 start/stop instant records"""
566 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
568 "instantRecord": (self.instantRecord, "Instant Record..."),
570 self.recording = None
572 self["BlinkingPoint"] = BlinkingPixmapConditional()
573 self.onShown.append(self["BlinkingPoint"].hideWidget)
574 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
576 def stopCurrentRecording(self):
577 self.session.nav.RecordTimer.removeEntry(self.recording)
578 self.recording = None
580 def startInstantRecording(self):
581 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
583 # try to get event info
586 service = self.session.nav.getCurrentService()
587 info = service.info()
588 ev = info.getEvent(0)
593 # fix me, description.
594 self.recording = self.session.nav.recordWithTimer(time.time(), time.time() + 3600, serviceref, epg, "instant record")
595 self.recording.dontSave = True
597 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
599 def isInstantRecordRunning(self):
600 if self.recording != None:
601 if self.recording.isRunning():
605 def recordQuestionCallback(self, answer):
609 if self.isInstantRecordRunning():
610 self.stopCurrentRecording()
612 self.startInstantRecording()
614 def instantRecord(self):
616 stat = os.stat("/hdd/movies")
618 self.session.open(MessageBox, "No HDD found!")
621 if self.isInstantRecordRunning():
622 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
624 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
626 from Screens.AudioSelection import AudioSelection
628 class InfoBarAudioSelection:
630 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
632 "audioSelection": (self.audioSelection, "Audio Options..."),
635 def audioSelection(self):
636 service = self.session.nav.getCurrentService()
637 audio = service.audioTracks()
638 n = audio.getNumberOfTracks()
640 self.session.open(AudioSelection, audio)
642 from Screens.SubserviceSelection import SubserviceSelection
644 class InfoBarSubserviceSelection:
646 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
648 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
651 def subserviceSelection(self):
652 service = self.session.nav.getCurrentService()
653 subservices = service.subServices()
654 n = subservices.getNumberOfSubservices()
656 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
658 def subserviceSelected(self, service):
659 if not service is None:
660 self.session.nav.playService(service)
662 class InfoBarAdditionalInfo:
664 self["DolbyActive"] = PixmapConditional()
665 # TODO: get the info from c++ somehow
666 self["DolbyActive"].setConnect(lambda: False)
668 self["CryptActive"] = PixmapConditional()
669 # TODO: get the info from c++ somehow
670 self["CryptActive"].setConnect(lambda: False)
672 self["FormatActive"] = PixmapConditional()
673 # TODO: get the info from c++ somehow
674 self["FormatActive"].setConnect(lambda: False)
676 self["ButtonRed"] = PixmapConditional(withTimer = False)
677 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
678 self.onShown.append(self["ButtonRed"].update)
679 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
680 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
681 self.onShown.append(self["ButtonRedText"].update)
683 self["ButtonGreen"] = PixmapConditional()
684 self["ButtonGreen"].setConnect(lambda: self.session.nav.getCurrentService().subServices().getNumberOfSubservices() > 0)
685 self["ButtonGreenText"] = LabelConditional(text = _("Subservices"))
686 self["ButtonGreenText"].setConnect(lambda: self.session.nav.getCurrentService().subServices().getNumberOfSubservices() > 0)
688 self["ButtonYellow"] = PixmapConditional()
689 self["ButtonYellow"].setConnect(lambda: False)
691 self["ButtonBlue"] = PixmapConditional()
692 self["ButtonBlue"].setConnect(lambda: False)
694 class InfoBarNotifications:
696 self.onExecBegin.append(self.checkNotifications)
697 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
699 def checkNotificationsIfExecing(self):
701 self.checkNotifications()
703 def checkNotifications(self):
704 if len(Notifications.notifications):
705 n = Notifications.notifications[0]
706 Notifications.notifications = Notifications.notifications[1:]
710 self.session.openWithCallback(cb, *n[1:])
712 self.session.open(*n[1:])