initial commit of the new teletext plugin
[enigma2-plugins.git] / teletext / src / plugin.py
1 from __init__ import _, _debug , _log
2
3 from enigma import iServiceInformation, iPlayableService, eSocketNotifier, getDesktop, eConsoleAppContainer, ePoint, eSize
4
5 from Screens.HelpMenu import HelpMenu
6 from Screens.MessageBox import MessageBox
7 from Screens.Screen import Screen
8 from Components.ActionMap import ActionMap, NumberActionMap
9 from Components.ConfigList import ConfigListScreen
10 from Components.Label import Label
11 from Components.Pixmap import Pixmap
12 from Components.ServiceEventTracker import ServiceEventTracker
13 from Components.config import config, configfile, getConfigListEntry, ConfigSubsection, ConfigEnableDisable, ConfigSlider, ConfigSelection, ConfigSequence
14 from GlobalActions import globalActionMap
15 from Plugins.Plugin import PluginDescriptor
16 from Tools.Directories import resolveFilename, SCOPE_PLUGINS
17
18 import array
19 import socket
20 import struct
21
22 from os import unlink
23 from select import POLLIN, POLLPRI, POLLHUP, POLLERR
24
25 from enigma import Teletext as TeletextInterface
26
27 CMD_CTL_CACHE=1
28 CMD_SHOW_PAGE=2
29 CMD_PAGE_NEXT=3
30 CMD_PAGE_PREV=4
31 CMD_SUBP_NEXT=5
32 CMD_SUBP_PREV=6
33 CMD_COLKEY_RD=7
34 CMD_COLKEY_GN=8
35 CMD_COLKEY_YE=9
36 CMD_COLKEY_BL=10
37 CMD_CATCHPAGE=11
38 CMD_CONCEALED=12
39 CMD_SET_BRIGH=13
40 CMD_SET_CONTR=14
41 CMD_RQ_UPDATE=15
42 CMD_RZAP_PAGE=16
43 CMD_OPAQUE=17
44 CMD_TRANSPARENCY=18
45 CMD_FLOF=19
46 CMD_PAGEINPUT=20
47 CMD_EDGE_CUT=21
48 CMD_TEXTLEVEL=22
49 CMD_CLOSE_DMN=99
50
51 SPLIT_MODE_PAT = "pat"
52 SPLIT_MODE_TAP = "tap"
53 SPLIT_MODE_TIP = "tip"
54 splittingModeList = [ (SPLIT_MODE_PAT, _("picture and teletext")), (SPLIT_MODE_TAP, _("teletext and picture")), (SPLIT_MODE_TIP, _("teletext in picture")) ]
55 textlevelModeList = [ ("0", "1.0"), ("1", "1.5"), ("2", "2.5"), ("3", "3.5") ]
56
57 HELP_TEXT_POS          = _("Enter values (left, top, right, bottom) or press TEXT to move and resize the teletext graphically.")
58 HELP_TEXT_TIP_POS      = _("Enter values (left, top, right, bottom) or press TEXT to move and resize the teletext graphically.")
59 HELP_TEXT_SPLITTING    = _("Select splitting mode.")
60 HELP_TEXT_BRIGHTNESS   = _("Select brightness.")
61 HELP_TEXT_CONTRAST     = _("Select contrast.")
62 HELP_TEXT_TRANSPARENCY = _("Select transparency.")
63 HELP_TEXT_EDGE_CUT     = _("Display first and last row.")
64 HELP_TEXT_MESSAGES     = _("Show message if no teletext available or exit silently.")
65 HELP_TEXT_DEBUG        = _("Print debug messages to /tmp/dbttcp.log.")
66 HELP_TEXT_TEXTLEVEL    = _("Select teletext version to use.")
67
68 dsk_size   = getDesktop(0).size()
69 dsk_width  = dsk_size.width()
70 dsk_height = dsk_size.height()  
71
72 MIN_W = 400
73 MIN_H = 300
74
75 NAV_MODE_TEXT          = 0
76 NAV_MODE_SIZE_TEXT     = 1
77 NAV_MODE_SIZE_TIP_TEXT = 2
78
79 config.plugins.TeleText = ConfigSubsection()
80 config.plugins.TeleText.brightness   = ConfigSlider(default=8,  increment=1, limits=(0,15))
81 config.plugins.TeleText.contrast     = ConfigSlider(default=12, increment=1, limits=(0,15))
82 config.plugins.TeleText.transparency = ConfigSlider(default=8,  increment=1, limits=(0,15))
83 config.plugins.TeleText.messages = ConfigEnableDisable(default=True)
84 config.plugins.TeleText.edge_cut = ConfigEnableDisable(default=False)
85 config.plugins.TeleText.splitting_mode = ConfigSelection(splittingModeList, default=SPLIT_MODE_PAT)
86 config.plugins.TeleText.textlevel      = ConfigSelection(textlevelModeList, default="2")
87 config.plugins.TeleText.debug    = ConfigEnableDisable(default=False)
88 config.plugins.TeleText.pos      = ConfigSequence(default=[0, 0, dsk_width, dsk_height], seperator = ",", limits = [(0,dsk_width>>3),(0,dsk_height>>3),(dsk_width-(dsk_width>>3),dsk_width),(dsk_height-(dsk_height>>3),dsk_height)])
89 config.plugins.TeleText.tip_pos  = ConfigSequence(default=[(dsk_width>>1)+(dsk_width>>2), (dsk_height>>1)+(dsk_height>>2), dsk_width, dsk_height], seperator = ",", limits = [(0,dsk_width-MIN_W),(0,dsk_height-MIN_H),(MIN_W,dsk_width),(MIN_H,dsk_height)])
90 # state
91 config.plugins.TeleText.textOnly = ConfigEnableDisable(default=True)
92 config.plugins.TeleText.opaque   = ConfigEnableDisable(default=False)
93
94 # global functions
95
96 def log(message):
97   _log(message)
98   if config.plugins.TeleText.debug.value:
99     _debug(message)
100
101 class TeleText(Screen):
102
103   isDM7025    = False
104   pageInput   = 0
105   hasText     = False
106   catchPage   = False
107   flofValue   = True
108   infoValue   = False
109   edgeValue   = False
110   opaqueValue = False
111   nav_mode    = NAV_MODE_TEXT
112
113   onChangedEntry = [ ]  
114
115   def __init__(self, session):
116     TeleText.skin = """<screen position="0,0" size="%d,%d" title="TeleText" flags="wfNoBorder"/>""" % (dsk_width, dsk_height)
117     Screen.__init__(self, session)
118
119     self.__event_tracker = ServiceEventTracker(screen = self, eventmap={
120       iPlayableService.evStart : self.serviceStarted,
121       iPlayableService.evEnd : self.serviceStopped,
122       iPlayableService.evUpdatedInfo : self.serviceInfoChanged,
123     })
124
125     self["actions"] = NumberActionMap(["OkCancelActions", "TeleTextActions"],
126     {
127       "ok" : self.okPressed,
128       "cancel" : self.cancelPressed,
129       "1" : self.keyNumberGlobal,
130       "2" : self.keyNumberGlobal,
131       "3" : self.keyNumberGlobal,
132       "4" : self.keyNumberGlobal,
133       "5" : self.keyNumberGlobal,
134       "6" : self.keyNumberGlobal,
135       "7" : self.keyNumberGlobal,
136       "8" : self.keyNumberGlobal,
137       "9" : self.keyNumberGlobal,
138       "0" : self.keyNumberGlobal,
139       "red":    self.redPressed,
140       "green":  self.greenPressed,
141       "yellow": self.yellowPressed,
142       "blue":   self.bluePressed,
143       "right":  self.rightPressed,
144       "left":   self.leftPressed,
145       "down":   self.downPressed,
146       "up":     self.upPressed,
147       "info":   self.infoPressed,
148       "tv":     self.tvPressed,
149       "radio":  self.radioPressed,
150       "text":   self.textPressed,
151       "menu":   self.menuPressed,
152       "help":   self.helpPressed,
153       "video":  self.videoPressed,
154       "nextBouquet": self.nextBouquetPressed,
155       "prevBouquet": self.prevBouquetPressed,
156       "volUp":       self.volumeUpPressed,
157       "volDown":     self.volumeDownPressed
158     }, -1)
159     self["actions"].setEnabled(True)
160
161     self.helpList.append((self["actions"], "TeleTextActions", [("1", _("enter page number"))]))
162     self.helpList.append((self["actions"], "TeleTextActions", [("2", _("enter page number"))]))
163     self.helpList.append((self["actions"], "TeleTextActions", [("3", _("enter page number"))]))
164     self.helpList.append((self["actions"], "TeleTextActions", [("4", _("enter page number"))]))
165     self.helpList.append((self["actions"], "TeleTextActions", [("5", _("enter page number"))]))
166     self.helpList.append((self["actions"], "TeleTextActions", [("6", _("enter page number"))]))
167     self.helpList.append((self["actions"], "TeleTextActions", [("7", _("enter page number"))]))
168     self.helpList.append((self["actions"], "TeleTextActions", [("8", _("enter page number"))]))
169     self.helpList.append((self["actions"], "TeleTextActions", [("9", _("enter page number / page 100"))]))
170     self.helpList.append((self["actions"], "TeleTextActions", [("0", _("enter page number / rezap"))]))
171     self.helpList.append((self["actions"], "OkCancelActions", [("cancel", _("exit"))]))
172     self.helpList.append((self["actions"], "OkCancelActions", [("ok", _("start page catching / select page"))]))
173 #    self.helpList.append((self["actions"], "TeleTextActions", [("volUp",_("increase width"))]))
174 #    self.helpList.append((self["actions"], "TeleTextActions", [("volDown",_("decrease width"))]))
175     self.helpList.append((self["actions"], "TeleTextActions", [("nextBouquet",_("increase height"))]))
176     self.helpList.append((self["actions"], "TeleTextActions", [("prevBouquet",_("decrease height"))]))
177     self.helpList.append((self["actions"], "TeleTextActions", [("info", _("toggle info"))]))
178     self.helpList.append((self["actions"], "TeleTextActions", [("menu", _("teletext settings"))]))
179     self.helpList.append((self["actions"], "TeleTextActions", [("up", _("next page / catch page / move"))]))
180     self.helpList.append((self["actions"], "TeleTextActions", [("left", _("prev sub page / move"))]))
181     self.helpList.append((self["actions"], "TeleTextActions", [("right", _("next sub page / move"))]))
182     self.helpList.append((self["actions"], "TeleTextActions", [("down", _("prev page / catch page / move"))]))
183     self.helpList.append((self["actions"], "TeleTextActions", [("video", _("toggle flof"))]))
184     self.helpList.append((self["actions"], "TeleTextActions", [("red", _("red teletext link"))]))
185     self.helpList.append((self["actions"], "TeleTextActions", [("green", _("green teletext link"))]))
186     self.helpList.append((self["actions"], "TeleTextActions", [("yellow", _("yellow teletext link"))]))
187     self.helpList.append((self["actions"], "TeleTextActions", [("blue", _("blue teletext link"))]))
188     self.helpList.append((self["actions"], "TeleTextActions", [("tv", _("split screen"))]))
189     self.helpList.append((self["actions"], "TeleTextActions", [("radio", _("toggle transparency"))]))
190     self.helpList.append((self["actions"], "TeleTextActions", [("text", _("exit"))]))
191
192     self.connected = False
193
194     self.ttx = TeletextInterface()
195
196     self.onLayoutFinish.append(self.__layoutFinished)
197     self.onExecBegin.append(self.__execBegin)
198     self.onClose.append(self.__closed)
199
200     self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
201     self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
202     try:
203       unlink('/tmp/dbttcp.socket')
204     except:
205       pass
206     self.socket.bind('/tmp/dbttcp.socket')
207     self.listen_sn = eSocketNotifier(self.socket.fileno(), POLLIN)
208     self.listen_sn.callback.append(self.listen_data_avail)
209     self.socket.listen(1)
210
211   def socketSend(self, buf):
212     log("send %s" % (buf))
213     try:
214       s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
215       s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
216       s.connect('/tmp/dbttcd.socket')
217       s.setblocking(0)
218       s.sendall(buf)
219       s.close()
220     except socket.error, msg:
221       log("couldn't send data to /tmp/dbttcd.socket")
222       log(socket.errno)
223       log(msg)
224 #      self.session.open(MessageBox, _("Daemon not running."), MessageBox.TYPE_ERROR, timeout = 3)
225 #      self.close()
226
227   def listen_data_avail(self, what):
228     conn, addr = self.socket.accept()
229     buf = conn.recv(8, socket.MSG_WAITALL)
230     x = array.array('H')
231     x.fromstring(buf)
232     if (x[0] + x[1] + x[2] + x[3]) == 0:
233       self.catchPage = False
234     else:
235 #      if (x[0] + x[1]) == 0:
236 #        log("recv update %s" % (x))
237       if not self.isDM7025:
238         self.ttx.update(x[0], x[1], x[2], x[3]);
239       conn.close()
240
241   def __execBegin(self):
242     log("execBegin")
243
244     self.updateLayout()
245
246     # send brightness, contrast and transparency...
247     self.sendSettings()
248
249     if self.isDM7025:
250       renderOffset = 0x75488
251       stride = 0xb80
252     else:
253       renderOffset = self.ttx.getRenderBufferOffset()
254       stride = self.ttx.getRenderBufferStride()
255
256     log("framebuffer offset is %08x stride is %08x" % (renderOffset, stride))
257     x = array.array('B', (CMD_RQ_UPDATE, 1, (renderOffset&0xFF000000)>>24, (renderOffset&0xFF0000)>>16, (renderOffset&0xFF00)>>8, renderOffset&0xFF, (stride&0xFF00) >> 8, stride&0xFF))
258     self.socketSend(x)
259
260   def __closed(self):
261     log("__closed")
262     if self.isDM7025:
263       renderOffset = 0x75488
264       stride = 0xb80
265     else:
266       renderOffset = self.ttx.getRenderBufferOffset()
267       stride = self.ttx.getRenderBufferStride()
268     x = array.array('B', (CMD_RQ_UPDATE, 0, (renderOffset&0xFF000000)>>24, (renderOffset&0xFF0000)>>16, (renderOffset&0xFF00)>>8, renderOffset&0xFF, (stride&0xFF00) >> 8, stride&0xFF))
269     self.socketSend(x)
270
271   def __layoutFinished(self):
272     log("__layoutFinished")
273     self.ttx.show(self.instance)
274
275   def keyNumberGlobal(self, number):
276     if self.nav_mode != NAV_MODE_TEXT or self.catchPage:
277       return
278     log("%s pressed" % (number))
279     x = array.array('B')
280     if self.pageInput == 0:
281       if number == 0:
282         x.append(CMD_RZAP_PAGE)
283       elif number == 9:
284         x.fromlist([CMD_SHOW_PAGE, 1, 0, 0])
285       else:
286         x.fromlist([CMD_PAGEINPUT, number])
287         self.pageInput = (self.pageInput + 1) % 3
288     else:
289       x.fromlist([CMD_PAGEINPUT, number])
290       self.pageInput = (self.pageInput + 1) % 3
291     self.socketSend(x)
292
293   def pageSet(self, page):
294     log("pageSet(%d)" % (page))
295     page = int("%d" % (page), 16)
296     x = array.array('B', (CMD_SHOW_PAGE, (page & 0xFF00) >> 8, (page&0xFF), 0))
297     self.socketSend(x)
298
299   def upPressed(self):
300     if self.nav_mode == NAV_MODE_TEXT:
301       if self.pageInput != 0:
302         return
303       log("up pressed")
304       if self.catchPage:
305         x = array.array('B', (CMD_CATCHPAGE, 2, 0))
306       else:
307         x = array.array('B')
308         x.append(CMD_PAGE_NEXT)
309       self.socketSend(x)
310     else:
311       if self.nav_pos[1] > 0 and self.nav_pos[3] > self.nav_config.limits[3][0]:
312         self.nav_pos[1] = self.nav_pos[1] - 1
313         self.nav_pos[3] = self.nav_pos[3] - 1
314       self.updateLayout()
315
316   def downPressed(self):
317     if self.nav_mode == NAV_MODE_TEXT:
318       if self.pageInput != 0:
319         return
320       log("down pressed")
321       if self.catchPage:
322         x = array.array('B', (CMD_CATCHPAGE, 2, 1))
323       else:
324         x = array.array('B')
325         x.append(CMD_PAGE_PREV)
326       self.socketSend(x)
327     else:
328       if self.nav_pos[1] < self.nav_config.limits[1][1] and self.nav_pos[3] < dsk_height:
329         self.nav_pos[1] = self.nav_pos[1] + 1
330         self.nav_pos[3] = self.nav_pos[3] + 1
331         self.updateLayout()
332
333   def leftPressed(self):
334     if self.nav_mode == NAV_MODE_TEXT:
335       if self.catchPage or self.pageInput != 0:
336         return
337       log("left pressed")
338       x = array.array('B')
339       x.append(CMD_SUBP_PREV)
340       self.socketSend(x)
341     else:
342       if self.nav_pos[0] > 0 and self.nav_pos[2] > self.nav_config.limits[2][0]:
343         self.nav_pos[0] = self.nav_pos[0] - 1
344         self.nav_pos[2] = self.nav_pos[2] - 1
345       self.updateLayout()
346
347   def rightPressed(self):
348     if self.nav_mode == NAV_MODE_TEXT:
349       if self.catchPage or self.pageInput != 0:
350         return
351       log("right pressed")
352       x = array.array('B')
353       x.append(CMD_SUBP_NEXT)
354       self.socketSend(x)
355     else:
356       if self.nav_pos[0] < self.nav_config.limits[0][1] and self.nav_pos[2] < dsk_width:
357         self.nav_pos[0] = self.nav_pos[0] + 1
358         self.nav_pos[2] = self.nav_pos[2] + 1
359         self.updateLayout()
360
361   def nextBouquetPressed(self):
362     if self.nav_mode == NAV_MODE_TEXT:
363       return
364     log("bouqet+ pressed")
365     if self.nav_pos[3] < dsk_height:
366       self.nav_pos[3] = self.nav_pos[3] + 1
367     elif self.nav_pos[1] > 0:
368       self.nav_pos[1] = self.nav_pos[1] - 1
369     self.updateLayout()
370
371   def prevBouquetPressed(self):
372     if self.nav_mode == NAV_MODE_TEXT:
373       return
374     log("bouquet- pressed")
375     if self.nav_pos[3] > (self.nav_pos[1] + MIN_H):
376       if self.nav_pos[3] > self.nav_config.limits[3][0]:
377         self.nav_pos[3] = self.nav_pos[3] - 1
378       elif self.nav_pos[1] < self.nav_config.limits[1][1]:
379         self.nav_pos[1] = self.nav_pos[1] + 1
380       self.updateLayout()
381
382   def volumeUpPressed(self):
383     if self.nav_mode == NAV_MODE_TEXT:
384       globalActionMap.action("TeleText", "volumeUp")
385       return
386     log("volume+ pressed")
387     if self.nav_pos[2] < dsk_width:
388       self.nav_pos[2] = self.nav_pos[2] + 1
389     elif self.nav_pos[0] > 0:
390       self.nav_pos[0] = self.nav_pos[0] - 1
391     self.updateLayout()
392
393   def volumeDownPressed(self):
394     if self.nav_mode == NAV_MODE_TEXT:
395       globalActionMap.action("TeleText", "volumeDown")
396       return
397     log("volume- pressed")
398     if self.nav_pos[2] > (self.nav_pos[0] + MIN_W):
399       if self.nav_pos[2] > self.nav_config.limits[2][0]:
400         self.nav_pos[2] = self.nav_pos[2] - 1
401       elif self.nav_pos[0] < self.nav_config.limits[0][1]:
402         self.nav_pos[0] = self.nav_pos[0] + 1
403     self.updateLayout()
404
405   def redPressed(self):
406     if self.nav_mode != NAV_MODE_TEXT or self.catchPage or self.pageInput != 0:
407       return
408     log("red pressed")
409     x = array.array('B')
410     x.append(CMD_COLKEY_RD)
411     self.socketSend(x)
412
413   def greenPressed(self):
414     if self.nav_mode != NAV_MODE_TEXT or self.catchPage or self.pageInput != 0:
415       return
416     log("green pressed")
417     x = array.array('B')
418     x.append(CMD_COLKEY_GN)
419     self.socketSend(x)
420
421   def yellowPressed(self):
422     if self.nav_mode != NAV_MODE_TEXT or self.catchPage or self.pageInput != 0:
423       return
424     log("yellow pressed")
425     x = array.array('B')
426     x.append(CMD_COLKEY_YE)
427     self.socketSend(x)
428
429   def bluePressed(self):
430     if self.nav_mode != NAV_MODE_TEXT or self.catchPage or self.pageInput != 0:
431       return
432     log("blue pressed")
433     x = array.array('B')
434     x.append(CMD_COLKEY_BL)
435     self.socketSend(x)
436
437   def infoPressed(self):
438     if self.nav_mode != NAV_MODE_TEXT or self.catchPage or self.pageInput != 0:
439       return
440     log("info pressed")
441     self.infoValue = not self.infoValue
442     for i in self.onChangedEntry:
443       i()
444     x = array.array('B')
445     x.append(CMD_CONCEALED)
446     self.socketSend(x)
447
448   def videoPressed(self):
449     if self.nav_mode != NAV_MODE_TEXT or self.catchPage or self.pageInput != 0:
450       return
451     log("video pressed")
452     self.flofValue = not self.flofValue
453     for i in self.onChangedEntry:
454       i()
455     x = array.array('B')
456     x.append(CMD_FLOF)
457     self.socketSend(x)
458
459   def tvPressed(self):
460     if self.nav_mode != NAV_MODE_TEXT:
461       return
462     log("tv pressed")
463     if config.plugins.TeleText.textOnly.value:
464       config.plugins.TeleText.textOnly.value = False
465     else:
466       config.plugins.TeleText.textOnly.value = True
467     config.plugins.TeleText.textOnly.save()
468     configfile.save()
469     self.updateLayout()
470
471   def radioPressed(self):
472     if self.nav_mode != NAV_MODE_TEXT or self.catchPage or self.pageInput != 0:
473       return
474     log("radio pressed")
475     if config.plugins.TeleText.opaque.value:
476       config.plugins.TeleText.opaque.value = False
477     else:
478       config.plugins.TeleText.opaque.value = True
479     config.plugins.TeleText.opaque.save()
480     configfile.save()
481     self.opaqueValue = config.plugins.TeleText.opaque.value
482     x = array.array('B')
483     x.append(CMD_OPAQUE)
484     self.socketSend(x)
485
486   def textPressed(self):
487     if self.nav_mode != NAV_MODE_TEXT or self.catchPage or self.pageInput != 0:
488       return
489     log("text pressed")
490     self.resetVideo()
491     self.__closed()
492     self.close()
493
494   def menuPressed(self):
495     if self.nav_mode != NAV_MODE_TEXT or self.catchPage or self.pageInput != 0:
496       return
497     log("menu pressed")
498     self.__closed()
499     self.resetVideo()
500     self.session.openWithCallback(self.menuResult, TeleTextMenu)
501
502   def menuResult(self, result):
503     if result is None:
504       return
505     
506     self.nav_text_only = config.plugins.TeleText.textOnly.value
507     self.nav_config = result
508     self.nav_orig_pos   = result.value
509     self.nav_pos    = result.value
510     
511     if result == config.plugins.TeleText.pos:
512       self.nav_mode = NAV_MODE_SIZE_TEXT
513       config.plugins.TeleText.textOnly.value = True
514     elif result == config.plugins.TeleText.tip_pos:
515       self.nav_mode = NAV_MODE_SIZE_TIP_TEXT
516       config.plugins.TeleText.textOnly.value = False
517       config.plugins.TeleText.textOnly.value = SPLIT_MODE_TIP
518     self.updateLayout()
519
520   def updateLayout(self):
521     if self.nav_mode == NAV_MODE_TEXT:
522       pos = config.plugins.TeleText.pos.value
523     else:
524       pos = self.nav_pos
525     right  = pos[2]
526     bottom = pos[3]
527     mode = config.plugins.TeleText.splitting_mode.value
528
529     if config.plugins.TeleText.textOnly.value == True:
530       left  = pos[0]
531       width  = right - left
532       top    = pos[1]
533       height = bottom - top
534       self.resetVideo()
535     elif mode == SPLIT_MODE_PAT:
536       left   = dsk_width>>1
537       width  = right - (dsk_width>>1)
538       top    = pos[1]
539       height = bottom - top
540       log("splitting video")
541       l=open("/proc/stb/vmpeg/0/dst_left","w")
542       l.write("%x" % 0)
543       l.close()
544       w=open("/proc/stb/vmpeg/0/dst_width","w")
545       w.write("%x" % 360)
546       w.close()
547     elif mode == SPLIT_MODE_TAP:
548       left   = pos[0]
549       width  = (dsk_width>>1) - left
550       top    = pos[1]
551       height = bottom - top
552       log("splitting video")
553       l=open("/proc/stb/vmpeg/0/dst_left","w")
554       l.write("%x" % 360)
555       l.close()
556       w=open("/proc/stb/vmpeg/0/dst_width","w")
557       w.write("%x" % 360)
558       w.close()
559     elif mode == SPLIT_MODE_TIP:
560       if self.nav_mode == NAV_MODE_TEXT:
561         pos = config.plugins.TeleText.tip_pos.value
562       left   = pos[0]
563       width  = pos[2] - left
564       top    = pos[1]
565       height = pos[3] - top
566       self.resetVideo()
567
568     log("screen rect %s %s %s %s" % (left, top, width, height))
569     self.instance.move(ePoint(left,top))
570     self.instance.resize(eSize(*(width, height)))
571
572     self.ttx.hide()
573     self.ttx.show(self.instance)
574     self.ttx.update(0,0,492,250)
575
576   def resetVideo(self):
577     log("reset video")
578     l=open("/proc/stb/vmpeg/0/dst_left","w")
579     l.write("%x" % 0)
580     l.close()
581     w=open("/proc/stb/vmpeg/0/dst_width","w")
582     w.write("%x" % 720)
583     w.close()
584
585   def sendSettings(self, result = True):
586     if result:
587       # Helligkeit
588       x = array.array('B')
589       x.append(CMD_SET_BRIGH)
590       x.append(config.plugins.TeleText.brightness.value<<4)
591       self.socketSend(x)
592       # Kontrast
593       x = array.array('B')
594       x.append(CMD_SET_CONTR)
595       x.append(config.plugins.TeleText.contrast.value<<4)
596       self.socketSend(x)
597       # Transparenz
598       x = array.array('B')
599       x.append(CMD_TRANSPARENCY)
600       x.append(config.plugins.TeleText.transparency.value<<4)
601       self.socketSend(x)
602       # edge cut
603       if self.edgeValue != config.plugins.TeleText.edge_cut.value:
604         self.edgeValue = config.plugins.TeleText.edge_cut.value
605         x = array.array('B')
606         x.append(CMD_EDGE_CUT)
607         self.socketSend(x)
608       # teletext level
609       x = array.array('B')
610       x.append(CMD_TEXTLEVEL)
611       x.append(int(config.plugins.TeleText.textlevel.value))
612       self.socketSend(x)
613       # opaque
614       if self.opaqueValue != config.plugins.TeleText.opaque.value:
615         self.opaqueValue = config.plugins.TeleText.opaque.value
616         x = array.array('B')
617         x.append(CMD_OPAQUE)
618         self.socketSend(x)
619
620   def helpPressed(self):
621     self.__closed()
622     self.resetVideo()
623     self.session.open(HelpMenu, self.helpList)     
624
625   def okPressed(self):
626     if self.nav_mode == NAV_MODE_TEXT:
627       if self.pageInput != 0:
628         return
629       log("ok pressed")
630       if self.catchPage:
631         x = array.array('B', (CMD_CATCHPAGE, 3, 1))
632         self.catchPage = False
633       else:
634         x = array.array('B', (CMD_CATCHPAGE, 1, 0))
635         self.catchPage = True
636       self.socketSend(x)
637     else:
638       if self.nav_mode == NAV_MODE_SIZE_TEXT:
639         config.plugins.TeleText.pos.value = self.nav_pos
640         config.plugins.TeleText.pos.save()
641       else:
642         config.plugins.TeleText.tip_pos.value = self.nav_pos
643         config.plugins.TeleText.tip_pos.save()
644       config.plugins.TeleText.textOnly.value = self.nav_text_only
645       del self.nav_text_only
646       del self.nav_config
647       del self.nav_orig_pos
648       del self.nav_pos
649       self.nav_mode = NAV_MODE_TEXT
650       self.updateLayout()
651
652   def cancelPressed(self):
653     if self.nav_mode == NAV_MODE_TEXT:
654       if self.pageInput != 0:
655         return
656       log("cancel pressed")
657       if self.catchPage:
658         x = array.array('B', (CMD_CATCHPAGE, 3, 0))
659         self.socketSend(x)
660         self.catchPage = False
661       else:
662         self.resetVideo()
663         self.__closed()
664         self.close()
665     else:
666       if self.nav_mode == NAV_MODE_SIZE_TEXT:
667         config.plugins.TeleText.pos.cancel()
668       else:
669         config.plugins.TeleText.tip_pos.cancel()
670       config.plugins.TeleText.textOnly.value = self.nav_text_only
671       del self.nav_text_only
672       del self.nav_config
673       del self.nav_orig_pos
674       del self.nav_pos
675       self.nav_mode = NAV_MODE_TEXT
676       self.updateLayout()
677
678   def serviceStarted(self):
679     log("service started")
680
681   def serviceStopped(self):
682     log("service stopped")
683     x = array.array('B', (CMD_CTL_CACHE, 0, 0, 0))
684     self.socketSend(x)
685
686   def serviceInfoChanged(self):
687     log("serviceInfoChanged")
688     service = self.session.nav.getCurrentService()
689     info = service and service.info()
690     txtpid = info and info.getInfo(iServiceInformation.sTXTPID)
691
692     self.hasText = txtpid is not None and txtpid > -1
693
694     stream = service and service.stream()
695     demux = stream and stream.getStreamingData()
696     demux = demux and demux.get("demux", -1)
697
698     log("TXT PID %s DEMUX %s" % (txtpid, demux))
699
700     if demux > -1 and self.hasText:
701       x = array.array('B', (CMD_CTL_CACHE, (txtpid & 0xFF00) >> 8, (txtpid&0xFF), demux))
702       self.socketSend(x)
703
704   def showMessages(self):
705     return config.plugins.TeleText.messages.value
706
707   # ---- for summary (lcd) ----
708
709   def createSummary(self):
710     return TeleTextSummary
711
712   def flofEnabled(self):
713     return self.flofValue
714     
715   def infoEnabled(self):
716     return self.infoValue
717
718 # ----------------------------------------
719
720 class TeleTextSummary(Screen):
721
722   def __init__(self, session, parent):
723     onPic  = resolveFilename(SCOPE_PLUGINS, "Extensions/TeleText/lcd_on.png")
724     offPic = resolveFilename(SCOPE_PLUGINS, "Extensions/TeleText/lcd_off.png")
725
726     TeleTextSummary.skin = """<screen name="TeleTextSummary" position="0,0" size="132,64">
727       <widget name="SetupTitle" position="6,4" size="120,20" font="Regular;20" halign="center"/>
728
729       <widget name="flof_off" position="24,28" size="20,20" pixmap="%s" zPosition="1"/>
730       <widget name="info_off" position="88,28" size="20,20" pixmap="%s" zPosition="1"/>
731       <widget name="flof_on"  position="24,28" size="20,20" pixmap="%s" zPosition="2"/>
732       <widget name="info_on"  position="88,28" size="20,20" pixmap="%s" zPosition="2"/>
733
734       <widget name="flof_txt" position="10,50" size="48,12" font="Regular;12" valign="center" halign="center" zPosition="1"/>
735       <widget name="info_txt" position="74,50" size="48,12" font="Regular;12" valign="center" halign="center" zPosition="1"/> 
736     </screen>""" % (offPic, offPic, onPic, onPic)
737
738     Screen.__init__(self, session, parent = parent)
739     self["SetupTitle"] = Label("TeleText")
740     self["flof_txt"] = Label("FLOF")
741     self["info_txt"] = Label("INFO")
742     self["flof_off"] = Pixmap()
743     self["info_off"] = Pixmap()
744     self["flof_on"]  = Pixmap()
745     self["info_on"]  = Pixmap()
746     self.onShow.append(self.addWatcher)
747     self.onHide.append(self.removeWatcher)
748
749   def addWatcher(self):
750     self.parent.onChangedEntry.append(self.selectionChanged)
751     self.selectionChanged()
752
753   def removeWatcher(self):
754     self.parent.onChangedEntry.remove(self.selectionChanged)
755
756   def selectionChanged(self):
757     if self.parent.flofEnabled():
758       self["flof_off"].hide()
759       self["flof_on"].show()
760     else:
761       self["flof_on"].hide()
762       self["flof_off"].show()
763
764     if self.parent.infoEnabled():
765       self["info_off"].hide()
766       self["info_on"].show()
767     else:
768       self["info_on"].hide()
769       self["info_off"].show()
770
771 # ----------------------------------------
772
773 class TeleTextMenu(ConfigListScreen, Screen):
774
775   onChangedEntry = [ ]
776   isInitialized = False
777
778   def __init__(self, session):
779     width = 492
780     height = 330
781     left = (dsk_width - width)>>1
782     top = (dsk_height - height)>>1
783     log("[menu] screen rect %s %s %s %s" % (left, top, width, height))
784     TeleTextMenu.skin = """<screen position="%d,%d" size="%d,%d" title="%s">
785         <widget name="config" position="0,0"   size="492,255" scrollbarMode="showOnDemand" zPosition="1"/>
786         <ePixmap pixmap="skin_default/div-h.png" position="0,260" zPosition="1" size="492,2" />
787         <widget name="label"  position="0,265" size="492,65" font="Regular;16" zPosition="1" halign="left" valign="top"/>
788       </screen>""" % (left, top, width, height, _("TeleText settings"))
789
790     Screen.__init__(self, session)
791
792     # create config list
793     self.list = [] 
794     ConfigListScreen.__init__(self, self.list) 
795     self.createConfigList()
796
797     self["actions"] = ActionMap(["OkCancelActions", "TeleTextActions"],
798     {
799       "ok"     : self.okPressed,
800       "cancel" : self.cancelPressed,
801       "menu"   : self.cancelPressed,
802       "text"   : self.textPressed
803     }, -2)
804     self["actions"].setEnabled(True)
805
806     self["label"] = Label("Info")
807
808     self.onLayoutFinish.append(self.__layoutFinished)
809
810   def __layoutFinished(self):
811     self.isInitialized = True
812     if not self.selectionChanged in self["config"].onSelectionChanged:
813       self["config"].onSelectionChanged.append(self.selectionChanged)
814     self.selectionChanged()     
815
816   def selectionChanged(self):
817     configele = self["config"].getCurrent()[1]
818     if configele == config.plugins.TeleText.pos:
819       self["label"].setText(HELP_TEXT_POS)
820     elif configele == config.plugins.TeleText.brightness:
821       self["label"].setText(HELP_TEXT_BRIGHTNESS)
822     elif configele == config.plugins.TeleText.contrast:
823       self["label"].setText(HELP_TEXT_CONTRAST)
824     elif configele == config.plugins.TeleText.transparency:
825       self["label"].setText(HELP_TEXT_TRANSPARENCY)
826     elif configele == config.plugins.TeleText.splitting_mode:
827       self["label"].setText(HELP_TEXT_SPLITTING)
828     elif configele == config.plugins.TeleText.tip_pos:
829       self["label"].setText(HELP_TEXT_TIP_POS)
830     elif configele == config.plugins.TeleText.messages:
831       self["label"].setText(HELP_TEXT_MESSAGES)
832     elif configele == config.plugins.TeleText.debug:
833       self["label"].setText(HELP_TEXT_DEBUG)
834     elif configele == config.plugins.TeleText.edge_cut:
835       self["label"].setText(HELP_TEXT_EDGE_CUT)
836     elif configele == config.plugins.TeleText.textlevel:
837       self["label"].setText(HELP_TEXT_TEXTLEVEL)
838
839   def createConfig(self, configele):
840     if not self.isInitialized:
841       return
842     self.createConfigList()
843
844   def createConfigList(self):
845     self.isInitialized = False
846
847     # remove notifiers
848     for x in self["config"].list:
849       x[1].clearNotifiers() 
850
851     self.list = [
852       getConfigListEntry(_("Brightness"),        config.plugins.TeleText.brightness),
853       getConfigListEntry(_("Contrast"),          config.plugins.TeleText.contrast),
854       getConfigListEntry(_("Transparency"),      config.plugins.TeleText.transparency),
855       getConfigListEntry(_("Text level"),        config.plugins.TeleText.textlevel),
856       getConfigListEntry(_("Position and size"), config.plugins.TeleText.pos),
857       getConfigListEntry(_("Display edges"),     config.plugins.TeleText.edge_cut),
858       getConfigListEntry(_("Splitting mode"),    config.plugins.TeleText.splitting_mode)
859     ]
860     if config.plugins.TeleText.splitting_mode.value == SPLIT_MODE_TIP:
861       self.list.append(getConfigListEntry("... %s" % _("Position and size"),   config.plugins.TeleText.tip_pos))
862     self.list.append(getConfigListEntry(_("Message"), config.plugins.TeleText.messages))
863     self.list.append(getConfigListEntry(_("Debug"),   config.plugins.TeleText.debug))
864
865     self["config"].list = self.list
866
867     # add notifiers (lcd, info)
868     for x in self["config"].list:
869       x[1].addNotifier(self.changedEntry)
870     # add notifiers (menu)
871     config.plugins.TeleText.splitting_mode.addNotifier(self.createConfig)
872
873     self.isInitialized = True
874
875   def textPressed(self):
876     log("[menu] text pressed")
877     if self["config"].getCurrent()[1] == config.plugins.TeleText.pos:
878       self.close(config.plugins.TeleText.pos)
879     elif self["config"].getCurrent()[1] == config.plugins.TeleText.tip_pos:
880       self.close(config.plugins.TeleText.tip_pos)
881
882   def okPressed(self):
883     log("[menu] ok pressed")
884     self.checkPositionValues(config.plugins.TeleText.pos)
885     self.checkPositionValues(config.plugins.TeleText.tip_pos)
886     for x in self["config"].list:
887       x[1].save()
888     configfile.save()
889     self.close(None) 
890
891   def checkPositionValues(self, configele):
892     pos = configele.value
893     log("... old pos: %s %s %s %s" % (pos[0], pos[1], pos[2], pos[3]))
894     update = False
895     if pos[0] > pos[2]:
896       i = pos[0]
897       pos[0] = pos[2]
898       pos[2] = i
899       update = True
900     if pos[1] > pos[3]:
901       i = pos[1]
902       pos[1] = pos[3]
903       pos[3] = i
904       update = True
905     if (pos[2] - pos[0]) < MIN_W:
906       pos[2] = pos[0] + MIN_W
907       update = True
908     if (pos[3] - pos[1]) < MIN_H:
909       pos[3] = pos[1] + MIN_H
910       update = True
911     if pos[2] > dsk_width:
912       pos[0] = pos[0] + dsk_width - pos[2]
913       pos[2] = dsk_width
914       update = True
915     if pos[3] > dsk_height:
916       pos[1] = pos[1] + dsk_height - pos[3]
917       pos[3] = dsk_height
918       update = True
919     log("... new pos: %s %s %s %s" % (pos[0], pos[1], pos[2], pos[3]))
920       
921     if update:
922       configele.setValue(pos)
923
924   def cancelPressed(self):
925     log("[menu] cancel pressed")
926     confirm = False
927     for x in self["config"].list:
928       confirm = confirm or x[1].isChanged()
929     if confirm:
930       self.session.openWithCallback(self.DiscardConfirm, MessageBox, _("Discard changes?"))
931     else:
932       self.close(None) 
933
934   def DiscardConfirm(self, result):
935     if result:
936       for x in self["config"].list:
937         if x[1].isChanged():
938           x[1].cancel()
939       self.close(None)
940
941   # ---- for summary (lcd) ----
942
943   def changedEntry(self, element=None):
944     for x in self.onChangedEntry:
945       x()
946
947   def getCurrentEntry(self):
948     return self["config"].getCurrent()[0]
949
950   def getCurrentValue(self):
951     return str(self["config"].getCurrent()[1].getText())
952
953   def createSummary(self):
954     return TeleTextMenuSummary
955
956 # ----------------------------------------
957
958 class TeleTextMenuSummary(Screen):
959   skin = """<screen name="TeleTextMenuSummary" position="0,0" size="132,64">
960       <widget name="SetupTitle" position="6,4"  size="120,20" font="Regular;20" halign="center"/>
961       <widget name="SetupEntry" position="6,30" size="120,12" font="Regular;12" halign="left"/>
962       <widget name="SetupValue" position="6,48" size="120,12" font="Regular;12" halign="right"/>
963     </screen>"""
964
965   def __init__(self, session, parent):
966     Screen.__init__(self, session, parent = parent)
967     self["SetupTitle"] = Label("TeleText")
968     self["SetupEntry"] = Label("")
969     self["SetupValue"] = Label("")
970     self.onShow.append(self.addWatcher)
971     self.onHide.append(self.removeWatcher)
972
973   def addWatcher(self):
974     self.parent.onChangedEntry.append(self.selectionChanged)
975     self.parent["config"].onSelectionChanged.append(self.selectionChanged)
976     self.selectionChanged()
977
978   def removeWatcher(self):
979     self.parent.onChangedEntry.remove(self.selectionChanged)
980     self.parent["config"].onSelectionChanged.remove(self.selectionChanged)
981
982   def selectionChanged(self):
983     self["SetupEntry"].text = self.parent.getCurrentEntry()
984     self["SetupValue"].text = self.parent.getCurrentValue() 
985
986 # ----------------------------------------
987
988 def sessionstart(reason, session):
989   log("----- sessionstart(%s) -----" % session)
990   # Daemon starten
991   container = eConsoleAppContainer()
992   container.execute("/usr/bin/dbttcd")
993   # Plugin initialisieren
994   global ttx_screen;
995   ttx_screen = session.instantiateDialog(TeleText)
996
997 def autostart(reason, **kwargs):
998   log("autostart(%s, %s)" % (reason, kwargs))
999   if reason == 0:
1000     pass
1001   elif reason == 1:
1002     pass
1003
1004 def mainText(session, **kwargs):
1005   global ttx_screen
1006   log("mainText")
1007   if ttx_screen.hasText:
1008     session.execDialog(ttx_screen)
1009   else:
1010     if ttx_screen.showMessages():
1011       session.open(MessageBox, _("No teletext available."), MessageBox.TYPE_INFO, timeout = 3)
1012
1013 def mainMenu(session, **kwargs):
1014   global ttx_screen
1015   log("mainMenu")
1016   session.open(TeleTextMenu)
1017
1018 def Plugins(**kwargs):
1019   log("plugins")
1020   return [
1021     PluginDescriptor(name="TeleText", description="teletext", where = PluginDescriptor.WHERE_TELETEXT, fnc=mainText),
1022     PluginDescriptor(needsRestart = False, where = PluginDescriptor.WHERE_SESSIONSTART, fnc=sessionstart),
1023     PluginDescriptor(needsRestart = False, where = PluginDescriptor.WHERE_AUTOSTART, fnc=autostart)
1024     ]
1025
1026 # EOF