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, [100], 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, True)
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, True)
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, True)
124 def delHideTimer(self):
131 self.state = self.STATE_SHOWN
132 self.hideTimer.start(5000, True)
134 def doTimerHide(self):
135 self.hideTimer.stop()
136 if self.state == self.STATE_SHOWN:
138 self.state = self.STATE_HIDDEN
140 def toggleShow(self):
141 if self.state == self.STATE_SHOWN:
143 #pls check animation support, sorry
145 self.hideTimer.stop()
146 self.state = self.STATE_HIDDEN
147 elif self.state == self.STATE_HIDDEN:
152 self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
153 self.state = self.STATE_SHOWN
156 self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
157 self.state = self.STATE_HIDDEN
159 class NumberZap(Screen):
166 self.close(int(self["number"].getText()))
168 def keyNumberGlobal(self, number):
169 self.Timer.start(3000, True) #reset timer
170 self.field = self.field + str(number)
171 self["number"].setText(self.field)
172 if len(self.field) >= 4:
175 def __init__(self, session, number):
176 Screen.__init__(self, session)
177 self.field = str(number)
179 self["channel"] = Label(_("Channel:"))
181 self["number"] = Label(self.field)
183 self["actions"] = NumberActionMap( [ "SetupActions" ],
187 "1": self.keyNumberGlobal,
188 "2": self.keyNumberGlobal,
189 "3": self.keyNumberGlobal,
190 "4": self.keyNumberGlobal,
191 "5": self.keyNumberGlobal,
192 "6": self.keyNumberGlobal,
193 "7": self.keyNumberGlobal,
194 "8": self.keyNumberGlobal,
195 "9": self.keyNumberGlobal,
196 "0": self.keyNumberGlobal
199 self.Timer = eTimer()
200 self.Timer.timeout.get().append(self.keyOK)
201 self.Timer.start(3000, True)
203 class InfoBarPowerKey:
204 """ PowerKey stuff - handles the powerkey press and powerkey release actions"""
207 self.powerKeyTimer = eTimer()
208 self.powerKeyTimer.timeout.get().append(self.powertimer)
209 self["PowerKeyActions"] = HelpableActionMap(self, "PowerKeyActions",
211 "powerdown": self.powerdown,
212 "powerup": self.powerup,
213 "discreteStandby": (self.standby, "Go standby"),
214 "discretePowerOff": (self.quit, "Go to deep standby"),
217 def powertimer(self):
218 print "PowerOff - Now!"
222 self.standbyblocked = 0
223 self.powerKeyTimer.start(3000, True)
226 self.powerKeyTimer.stop()
227 if self.standbyblocked == 0:
228 self.standbyblocked = 1
232 self.session.open(Standby, self)
238 class InfoBarNumberZap:
239 """ Handles an initial number for NumberZapping """
241 self["NumberZapActions"] = NumberActionMap( [ "NumberZapActions"],
243 "1": self.keyNumberGlobal,
244 "2": self.keyNumberGlobal,
245 "3": self.keyNumberGlobal,
246 "4": self.keyNumberGlobal,
247 "5": self.keyNumberGlobal,
248 "6": self.keyNumberGlobal,
249 "7": self.keyNumberGlobal,
250 "8": self.keyNumberGlobal,
251 "9": self.keyNumberGlobal,
252 "0": self.keyNumberGlobal,
255 def keyNumberGlobal(self, number):
256 # print "You pressed number " + str(number)
258 self.session.nav.zapLast()
262 self.session.openWithCallback(self.numberEntered, NumberZap, number)
264 def numberEntered(self, retval):
265 # print self.servicelist
267 self.zapToNumber(retval)
269 def searchNumberHelper(self, serviceHandler, num, bouquet):
270 servicelist = serviceHandler.list(bouquet)
271 if not servicelist is None:
273 serviceIterator = servicelist.getNext()
274 if not serviceIterator.valid(): #check end of list
276 if serviceIterator.flags: #assume normal dvb service have no flags set
279 if not num: #found service with searched number ?
280 return serviceIterator, 0
283 def zapToNumber(self, number):
284 bouquet = self.servicelist.bouquet_root
286 serviceHandler = eServiceCenter.getInstance()
287 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
288 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
290 bouquetlist = serviceHandler.list(bouquet)
291 if not bouquetlist is None:
293 bouquet = bouquetlist.getNext()
294 if not bouquet.valid(): #check end of list
296 if ((bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory):
298 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
299 if not service is None:
300 self.session.nav.playService(service) #play service
301 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
302 self.servicelist.setRoot(bouquet)
303 self.servicelist.setCurrentSelection(service) #select the service in servicelist
305 class InfoBarChannelSelection:
306 """ ChannelSelection - handles the channelSelection dialog and the initial
307 channelChange actions which open the channelSelection dialog """
310 self.servicelist = self.session.instantiateDialog(ChannelSelection)
312 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
314 "switchChannelUp": self.switchChannelUp,
315 "switchChannelDown": self.switchChannelDown,
316 "zapUp": (self.zapUp, _("next channel")),
317 "zapDown": (self.zapDown, _("previous channel")),
320 def switchChannelUp(self):
321 self.servicelist.moveUp()
322 self.session.execDialog(self.servicelist)
324 def switchChannelDown(self):
325 self.servicelist.moveDown()
326 self.session.execDialog(self.servicelist)
329 self.servicelist.moveUp()
330 self.servicelist.zap()
335 self.servicelist.moveDown()
336 self.servicelist.zap()
341 """ Handles a menu action, to open the (main) menu """
343 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
345 "mainMenu": (self.mainMenu, "Enter main menu..."),
349 print "loading mainmenu XML..."
350 menu = mdom.childNodes[0]
351 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
352 self.session.open(MainMenu, menu, menu.childNodes)
355 """ EPG - Opens an EPG list when the showEPGList action fires """
357 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
359 "showEPGList": (self.showEPGList, _("show EPG...")),
362 def showEPGList(self):
363 ref=self.session.nav.getCurrentlyPlayingServiceReference()
364 ptr=eEPGCache.getInstance()
365 if ptr.startTimeQuery(ref) != -1:
366 self.session.open(EPGSelection, ref)
367 else: # try to show now/next
368 print 'no epg for service', ref.toString()
371 service = self.session.nav.getCurrentService()
372 info = service.info()
375 self.epglist.append(ptr)
378 self.epglist.append(ptr)
379 if len(self.epglist) > 0:
380 self.session.open(EventView, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
384 def eventViewCallback(self, setEvent, val): #used for now/next displaying
385 if len(self.epglist) > 1:
386 tmp = self.epglist[0]
387 self.epglist[0]=self.epglist[1]
389 setEvent(self.epglist[0])
394 """provides a snr/agc/ber display"""
396 self["snr"] = Label()
397 self["agc"] = Label()
398 self["ber"] = Label()
399 self["snr_percent"] = Label()
400 self["agc_percent"] = Label()
401 self["ber_count"] = Label()
402 self["snr_progress"] = ProgressBar()
403 self["agc_progress"] = ProgressBar()
404 self["ber_progress"] = ProgressBar()
405 self.timer = eTimer()
406 self.timer.timeout.get().append(self.updateTunerInfo)
407 self.timer.start(1000)
413 return (long)(log(val)/log(2))
416 def updateTunerInfo(self):
417 if self.instance.isVisible():
418 service = self.session.nav.getCurrentService()
422 if service is not None:
423 feinfo = service.frontendStatusInfo()
424 if feinfo is not None:
425 ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
426 snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
427 agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
428 self["snr_percent"].setText("%d%%"%(snr))
429 self["agc_percent"].setText("%d%%"%(agc))
430 self["ber_count"].setText("%d"%(ber))
431 self["snr_progress"].setValue(snr)
432 self["agc_progress"].setValue(agc)
433 self["ber_progress"].setValue(self.calc(ber))
436 """provides a current/next event info display"""
438 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
439 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
441 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
442 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
444 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Duration)
445 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
447 class InfoBarServiceName:
449 self["ServiceName"] = ServiceName(self.session.nav)
453 # ispause, isff, issm, skip
454 SEEK_STATE_PLAY = (0, 0, 0, 0)
455 SEEK_STATE_PAUSE = (1, 0, 0, 0)
456 SEEK_STATE_FF_2X = (0, 2, 0, 0)
457 SEEK_STATE_FF_4X = (0, 4, 0, 0)
458 SEEK_STATE_FF_8X = (0, 8, 0, 0)
459 SEEK_STATE_FF_32X = (0, 4, 0, 32)
460 SEEK_STATE_FF_64X = (0, 4, 0, 64)
461 SEEK_STATE_FF_128X = (0, 4, 0, 128)
463 SEEK_STATE_BACK_4X = (0, 0, 0, -4)
464 SEEK_STATE_BACK_32X = (0, 0, 0, -32)
465 SEEK_STATE_BACK_64X = (0, 0, 0, -64)
466 SEEK_STATE_BACK_128X = (0, 0, 0, -128)
468 SEEK_STATE_SM_HALF = (0, 0, 2, 0)
469 SEEK_STATE_SM_QUARTER = (0, 0, 4, 0)
470 SEEK_STATE_SM_EIGHTH = (0, 0, 8, 0)
472 """handles PVR specific actions like seeking, pause"""
474 self["PVRActions"] = HelpableActionMap(self, "InfobarPVRActions",
476 "pauseService": (self.pauseService, "pause"),
477 "unPauseService": (self.unPauseService, "continue"),
479 "seekFwd": (self.seekFwd, "skip forward"),
480 "seekBack": (self.seekBack, "skip backward"),
483 self.seekstate = self.SEEK_STATE_PLAY
484 self.seekTimer = eTimer()
485 self.seekTimer.timeout.get().append(self.seekTimerFired)
486 self.skipinterval = 500 # 500ms skip interval
487 self.onClose.append(self.delSeekTimer)
489 def delSeekTimer(self):
492 def seekTimerFired(self):
493 self.seekbase += self.skipmode * self.skipinterval
495 # check if we bounced against the beginning of the file
496 if self.seekbase < 0:
498 self.setSeekState(self.SEEK_STATE_PLAY)
500 self.doSeek(self.seekbase)
502 def setSeekState(self, state):
503 oldstate = self.seekstate
505 self.seekstate = state
507 service = self.session.nav.getCurrentService()
511 pauseable = service.pause()
514 if oldstate[i] != self.seekstate[i]:
515 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion, self.setSkipMode)[i](self.seekstate[i])
517 def setSkipMode(self, skipmode):
518 self.skipmode = skipmode
520 self.seekTimer.stop()
522 self.seekTimer.start(500)
524 service = self.session.nav.getCurrentService()
528 seekable = service.seek()
533 seekable.setTrickmode(1)
535 seekable.setTrickmode(0)
537 self.seekbase = seekable.getPlayPosition()[1] / 90
539 def pauseService(self):
540 self.setSeekState(self.SEEK_STATE_PAUSE);
542 def unPauseService(self):
543 self.setSeekState(self.SEEK_STATE_PLAY);
545 def doSeek(self, seektime):
546 service = self.session.nav.getCurrentService()
550 seekable = service.seek()
553 seekable.seekTo(90 * seektime)
557 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
558 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
559 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
560 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
561 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
562 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
563 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
564 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
565 self.SEEK_STATE_BACK_4X: self.SEEK_STATE_PLAY,
566 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_4X,
567 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
568 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
569 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
570 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
571 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
573 self.setSeekState(lookup[self.seekstate]);
577 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_4X,
578 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
579 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
580 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
581 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
582 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
583 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
584 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
585 self.SEEK_STATE_BACK_4X: self.SEEK_STATE_BACK_32X,
586 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
587 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
588 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
589 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
590 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
591 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
593 self.setSeekState(lookup[self.seekstate]);
595 from RecordTimer import parseEvent
597 class InfoBarInstantRecord:
598 """Instant Record - handles the instantRecord action in order to
599 start/stop instant records"""
601 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
603 "instantRecord": (self.instantRecord, "Instant Record..."),
605 self.recording = None
607 self["BlinkingPoint"] = BlinkingPixmapConditional()
608 self.onShown.append(self["BlinkingPoint"].hideWidget)
609 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
611 def stopCurrentRecording(self):
612 self.session.nav.RecordTimer.removeEntry(self.recording)
613 self.recording = None
615 def startInstantRecording(self):
616 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
618 # try to get event info
621 service = self.session.nav.getCurrentService()
622 info = service.info()
623 ev = info.getEvent(0)
628 if event is not None:
629 data = parseEvent(event)
630 data = (data[0], data[1] + 3600 * 10, data[2], data[3], data[4])
632 data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
634 # fix me, description.
635 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
636 self.recording.dontSave = True
638 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
640 def isInstantRecordRunning(self):
641 if self.recording != None:
642 if self.recording.isRunning():
646 def recordQuestionCallback(self, answer):
650 if self.isInstantRecordRunning():
651 self.stopCurrentRecording()
653 self.startInstantRecording()
655 def instantRecord(self):
657 stat = os.stat("/hdd/movies")
659 self.session.open(MessageBox, "No HDD found!")
662 if self.isInstantRecordRunning():
663 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
665 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
667 from Screens.AudioSelection import AudioSelection
669 class InfoBarAudioSelection:
671 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
673 "audioSelection": (self.audioSelection, "Audio Options..."),
676 def audioSelection(self):
677 service = self.session.nav.getCurrentService()
678 audio = service.audioTracks()
679 n = audio.getNumberOfTracks()
681 self.session.open(AudioSelection, audio)
683 from Screens.SubserviceSelection import SubserviceSelection
685 class InfoBarSubserviceSelection:
687 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
689 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
692 def subserviceSelection(self):
693 service = self.session.nav.getCurrentService()
694 subservices = service.subServices()
695 n = subservices.getNumberOfSubservices()
697 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
699 def subserviceSelected(self, service):
700 if not service is None:
701 self.session.nav.playService(service)
703 class InfoBarAdditionalInfo:
705 self["DolbyActive"] = PixmapConditional()
706 # TODO: get the info from c++ somehow
707 self["DolbyActive"].setConnect(lambda: False)
709 self["CryptActive"] = PixmapConditional()
710 # TODO: get the info from c++ somehow
711 self["CryptActive"].setConnect(lambda: False)
713 self["FormatActive"] = PixmapConditional()
714 # TODO: get the info from c++ somehow
715 self["FormatActive"].setConnect(lambda: False)
717 self["ButtonRed"] = PixmapConditional(withTimer = False)
718 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
719 self.onShown.append(self["ButtonRed"].update)
720 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
721 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
722 self.onShown.append(self["ButtonRedText"].update)
724 self["ButtonGreen"] = PixmapConditional()
725 self["ButtonGreen"].setConnect(lambda: self.session.nav.getCurrentService().subServices().getNumberOfSubservices() > 0)
726 self["ButtonGreenText"] = LabelConditional(text = _("Subservices"))
727 self["ButtonGreenText"].setConnect(lambda: self.session.nav.getCurrentService().subServices().getNumberOfSubservices() > 0)
729 self["ButtonYellow"] = PixmapConditional()
730 self["ButtonYellow"].setConnect(lambda: False)
732 self["ButtonBlue"] = PixmapConditional()
733 self["ButtonBlue"].setConnect(lambda: False)
735 class InfoBarNotifications:
737 self.onExecBegin.append(self.checkNotifications)
738 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
740 def checkNotificationsIfExecing(self):
742 self.checkNotifications()
744 def checkNotifications(self):
745 if len(Notifications.notifications):
746 n = Notifications.notifications[0]
747 Notifications.notifications = Notifications.notifications[1:]
751 self.session.openWithCallback(cb, *n[1:])
753 self.session.open(*n[1:])