[ShowClock]Close possibly opened keypad window when "Help" or "Move clock" button...
[enigma2-plugins.git] / showclock / src / plugin.py
1 # -*- coding: utf-8 -*-
2 #
3 #  Show Clock E2
4 #
5 #  $Id$
6 #
7 #  Coded by JuSt611  2011
8 #  Derived from Permanent Clock plugin written by AliAbdul
9 #  and placed in the public domain. He has my thanks.
10 #  Support: http://www.i-have-a-dreambox.com/wbb2/thread.php?threadid=???
11 #
12 #  Provided with no warranties of any sort.
13 #
14 #  This plugin is licensed under the Creative Commons 
15 #  Attribution-NonCommercial-ShareAlike 3.0 Unported 
16 #  License. To view a copy of this license, visit
17 #  http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
18 #  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
19 #
20 #  Alternatively, this plugin may be distributed and executed on hardware which
21 #  is licensed by Dream Multimedia GmbH.
22
23 #  This plugin is NOT free software. It is open source, you are allowed to
24 #  modify it (if you keep the license), but it may not be commercially 
25 #  distributed other than under the conditions noted above.
26 #
27
28 # for localized messages
29 from . import _
30
31 from enigma import ePoint, eTimer, getDesktop
32
33 # MessageBox
34 from Screens.MessageBox import MessageBox
35 from Tools import Notifications
36
37 # ActionMap
38 from Components.ActionMap import ActionMap
39 from GlobalActions import globalActionMap
40
41 # GUI (Components)
42 from Components.Sources.StaticText import StaticText
43
44 # KeynMap
45 from keymapparser import readKeymap, removeKeymap
46
47 # Configuration
48 from Components.config import config, getConfigListEntry, ConfigSubsection, ConfigSelection, ConfigText, ConfigNumber
49 from Components.Sources.StaticText import StaticText
50
51 # Plugin definition
52 from Plugins.Plugin import PluginDescriptor
53
54 # GUI (Screens)
55 from Screens.Screen import Screen
56 from Components.ConfigList import ConfigListScreen
57 from Screens.PiPSetup import clip
58
59 # GUI (Summary)
60 from Screens.Setup import SetupSummary
61
62
63 ###############################################################################        
64 VERSION = "0.4"
65 # History:
66 # 0.4 First public version
67
68 pluginPrintname = "[ShowClock Ver. %s]" %VERSION
69 debug = False # If set True, plugin will print some additional status info to track logic flow
70 ###############################################################################
71
72 config.plugins.ShowClock = ConfigSubsection()
73 config.plugins.ShowClock.name = ConfigText(default = _('Show Clock setup'), fixed_size = False, visible_width = 80)
74 config.plugins.ShowClock.description = ConfigText(default = _('Push "Exit" long to show/hide clock'), fixed_size = False, visible_width = 80)
75 config.plugins.ShowClock.menu = ConfigSelection(default = 'plugin', choices = [('plugin', _('Plugin menu')), ('extensions', _('Extensions menu'))])
76 config.plugins.ShowClock.showTimeout = ConfigNumber(default = 10)
77
78 width = getDesktop(0).size().width()
79 height = getDesktop(0).size().height()
80 config.plugins.ShowClock.position_x = ConfigNumber(default = int(width * 0.7))
81 config.plugins.ShowClock.position_y = ConfigNumber(default=45)
82 if debug: print pluginPrintname, "Clock X,Y position: %d,%d" %(config.plugins.ShowClock.position_x.value, config.plugins.ShowClock.position_y.value)
83
84 ##############################################################################
85
86 class ShowClockSetup(Screen, ConfigListScreen): # config
87
88         skin = """
89                 <screen name="ShowClock" position="center,center" size="600,290" title="Show Clock Setup" >
90                         <ePixmap pixmap="skin_default/buttons/red.png" position="5,5" zPosition="0" size="140,40" transparent="1" alphatest="on" />
91                         <ePixmap pixmap="skin_default/buttons/green.png" position="155,5" zPosition="0" size="140,40" transparent="1" alphatest="on" />
92                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="305,5" zPosition="0" size="140,40" transparent="1" alphatest="on" />
93                         <ePixmap pixmap="skin_default/buttons/blue.png" position="455,5" zPosition="0" size="140,40" transparent="1" alphatest="on" />
94                         
95                         <widget render="Label" source="key_red" position="5,5" size="140,40" zPosition="2" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
96                         <widget render="Label" source="key_green" position="155,5" size="140,40" zPosition="2" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
97                         <widget render="Label" source="key_yellow" position="305,5" size="140,40" zPosition="2" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
98                         <widget render="Label" source="key_blue" position="455,5" size="140,40" zPosition="2" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
99
100                         <widget name="config" position="5,60" size="590,105" scrollbarMode="showOnDemand" />
101
102                         <ePixmap pixmap="skin_default/div-h.png" position="0,170" zPosition="1" size="600,2" />
103                         <widget source="help" render="Label" position="5,185" size="590,100" font="Regular;21" /> 
104                 </screen>"""
105
106         def __init__(self, session):
107
108                 Screen.__init__(self, session)
109                 self.session = session
110                 #Summary
111                 self.setup_title = _("Show Clock Setup")
112
113                 self.onChangedEntry = []
114                 
115                 self.list = [   
116                         getConfigListEntry(_('Clock show timeout'), config.plugins.ShowClock.showTimeout,
117                                 _('Specify how long (seconds) the clock shall be shown before it disappears. Set to "0" to show clock until hidden manually.')),
118                         getConfigListEntry(_('Show in'), config.plugins.ShowClock.menu,
119                                 _('Specify whether plugin shall show up in plugin menu or extensions menu (needs GUI restart)')),
120                         getConfigListEntry(_('Name'), config.plugins.ShowClock.name,
121                                 _('Specify plugin name to be used in menu (needs GUI restart).')),
122                         getConfigListEntry(_("Description"), config.plugins.ShowClock.description,
123                                 _('Specify plugin description to be used in menu (needs GUI restart).')),       
124                         ]
125                                                         
126                 ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
127                 
128                 def selectionChanged():
129                         if self["config"].current:
130                                 self["config"].current[1].onDeselect(self.session)
131                         self["config"].current = self["config"].getCurrent()
132                         if self["config"].current:
133                                 self["config"].current[1].onSelect(self.session)
134                         for x in self["config"].onSelectionChanged:
135                                 x()
136                                 
137                 self["config"].selectionChanged = selectionChanged
138                 self["config"].onSelectionChanged.append(self.configHelp)
139
140                 # Initialize Buttons
141                 self["key_red"] = StaticText(_("Cancel"))
142                 self["key_green"] = StaticText(_("OK"))
143                 self["key_yellow"] = StaticText(_("Help"))
144                 self["key_blue"] = StaticText(_("Move clock"))
145
146                 self["help"] = StaticText()             
147
148                 # Define Actions                
149                 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
150                         {
151                         "red": self.keyCancel,
152                         "green": self.keySave,
153                         "yellow": self.keyHelp,
154                         "blue": self.keyMove,
155                         "cancel": self.keyCancel,
156                         "save": self.keySave,
157                         "ok": self.keySave,
158                         }, -2)
159
160                 # Trigger change
161                 self.changed()
162
163                 self.onLayoutFinish.append(self.setCustomTitle)
164
165         def setCustomTitle(self):
166                 self.setTitle(' '.join((_("Show Clock Setup"), _("Ver."), VERSION)))
167
168         def configHelp(self):
169                 self["help"].text = self["config"].getCurrent()[2]
170
171         def changed(self):
172                 for x in self.onChangedEntry:
173                         try:
174                                 x()
175                         except Exception:
176                                 pass    
177                         
178         def getCurrentEntry(self):
179                 return self["config"].getCurrent()[0]
180
181         def getCurrentValue(self):
182                 return str(self["config"].getCurrent()[1].getText())
183                 
184         def keyCancel(self):
185                 self.hideKeypad() # close help window if open
186                 ConfigListScreen.keyCancel(self)
187
188         def keySave(self):
189                 self.hideKeypad() # close help window if open
190                 ConfigListScreen.keySave(self)
191                                                 
192         def hideKeypad(self):
193                 try:
194                         self["config"].getCurrent()[1].help_window.instance.hide()
195                 except AttributeError:
196                         pass
197                                                 
198         def createSummary(self):
199                 return SetupSummary
200                 
201         def keyHelp(self):
202                 self.hideKeypad() # close help window if open
203                 self.session.open(MessageBox,
204                         _('Modify the settings to match your preferences. To change the clock position, select "Move clock" and relocate using the direction keys. Press OK to store current position and return to the setup menu or EXIT to cancel the moving.\n\nPush key "Exit long" to show the clock while watching TV. Clock will disappear after the specified timeout or by pushing key "Exit long" again.\n\nIf GP3 is installed, weekday shows up in selected language, otherwise always in english.'), 
205                         MessageBox.TYPE_INFO)
206                 
207         def keyMove(self):            
208                 if debug: print pluginPrintname, "Move Clock"
209                 self.hideKeypad() # close help window if open
210                 self.session.openWithCallback(
211                         self.startPositioner, MessageBox,
212                         _("Please use direction keys to move the clock.\n\nPress OK to store current position and return to the setup menu or EXIT to cancel the moving."),
213                         type=MessageBox.TYPE_INFO, timeout=10
214                 )
215                 
216         def startPositioner(self, answer):                      
217                 self.session.open(ShowClockPositioner)
218
219 ##############################################################################
220
221 class ShowClockPositioner(Screen):
222         def __init__(self, session):
223                 Screen.__init__(self, session)           
224                 self.skin = clockSkin()              
225                 self["actions"] = ActionMap(["PiPSetupActions"],
226                 {
227                         "left": self.left,
228                         "up": self.up,
229                         "right": self.right,
230                         "down": self.down,
231                         "ok": self.ok,
232                         "cancel": self.cancel                                                                                  
233                 }, -1)
234                 
235                 self.onShow.append(self.setPosition)
236
237         def setPosition(self):
238                 self.pos = (config.plugins.ShowClock.position_x.value, config.plugins.ShowClock.position_y.value)
239                 self.limit = (width - self.instance.size().width(), height - self.instance.size().height())
240                 if debug: print pluginPrintname, "Clock X,Y limit: %d,%d" %(self.limit[0], self.limit[1])       
241                 self.instance.move(ePoint(min(self.pos[0], self.limit[0]), min(self.pos[1], self.limit[1]))) # ensure clock visabilty even if resolution has changed
242         
243         def moveRelative(self, x = 0, y = 0):
244                 self.pos = (clip(self.pos[0] + x, 0, self.limit[0]), clip(self.pos[1] + y, 0, self.limit[1]))
245                 self.instance.move(ePoint(self.pos[0], self.pos[1]))
246
247         def left(self):
248                 self.moveRelative(x =- 10)
249
250         def up(self):
251                 self.moveRelative(y =- 10)
252
253         def right(self):
254                 self.moveRelative(x =+ 10)
255
256         def down(self):
257                 self.moveRelative(y =+ 10)
258
259         def ok(self):
260                 config.plugins.ShowClock.position_x.value = self.pos[0]
261                 config.plugins.ShowClock.position_x.save()
262                 config.plugins.ShowClock.position_y.value = self.pos[1]
263                 config.plugins.ShowClock.position_y.save()
264                 self.close()
265
266         def cancel(self):
267                 self.close()
268                 
269 ##############################################################################
270
271 class ShowClock(Screen):
272
273         def __init__(self, session):
274                 Screen.__init__(self, session)
275                 self.skin = clockSkin()                                 
276                 self.onShow.append(self.setPosition)
277
278         def setPosition(self):
279                 self.instance.move(ePoint( \
280                         min(config.plugins.ShowClock.position_x.value, width - self.instance.size().width()), \
281                         min(config.plugins.ShowClock.position_y.value, height - self.instance.size().height()) \
282                         )) # ensure clock visabilty even if resolution has changed     
283
284 ##############################################################################
285
286 class ShowClockMain():
287         def __init__(self):
288                 self.dialog = None
289                 self.clockShown = False
290
291         def gotSession(self, session):
292                 self.timer = eTimer() # check timer
293                 self.timer.callback.append(self.ShowHide)
294                 global globalActionMap
295                 readKeymap("/usr/lib/enigma2/python/Plugins/Extensions/ShowClock/keymap.xml")
296                 self.dialog = session.instantiateDialog(ShowClock)
297                 globalActionMap.actions['showClock'] = self.ShowHide
298                 
299         def ShowHide(self):
300                 if self.clockShown:
301                         if self.timer.isActive(): # stop timer if running
302                                 self.timer.stop()
303                         self.clockShown = False
304                         showClock.dialog.hide()
305                 else:
306                         self.clockShown = True
307                         if config.plugins.ShowClock.showTimeout.value > 0:
308                                 self.timer.startLongTimer(config.plugins.ShowClock.showTimeout.value)
309                         showClock.dialog.show()
310                 
311 showClock = ShowClockMain()
312
313 ##############################################################################
314
315 def clockSkin():
316
317         clockSkinSD = """
318                 <screen name="ShowClock" size="190,60" zPosition="10" backgroundColor="#50202020" flags="wfNoBorder">
319                         <widget source="global.CurrentTime" render="Label" position="55,12" size="58,17" font="Regular;21" halign="left" valign="center" transparent="1">
320                                 <convert type="ClockToText">Default</convert>
321                         </widget>
322                         <widget source="global.CurrentTime" render="Label" position="111,15" size="30,15" font="Regular;16" halign="left" valign="center" transparent="1">
323                                 <convert type="ClockToText">Format::%S</convert>
324                         </widget>
325                         <widget source="global.CurrentTime" render="Label" position="0,37" size="190,13" font="Regular;15" halign="center" valign="center" foregroundColor="#999999" transparent="1">
326                                 <convert type="ClockToText">Format:%A, %d.%m.%Y</convert>               
327                         </widget>
328                 </screen>"""
329                 
330         clockSkinXD = """
331                 <screen name="ShowClock" size="250,70" zPosition="10" backgroundColor="#50202020" flags="wfNoBorder">
332                         <widget source="global.CurrentTime" render="Label" position="80,10" size="80,25" font="Regular;24" halign="left" valign="center" transparent="1">
333                                 <convert type="ClockToText">Default</convert>
334                         </widget>
335                         <widget source="global.CurrentTime" render="Label" position="142,15" size="40,18" font="Regular;20" halign="left" valign="center" transparent="1">
336                                 <convert type="ClockToText">Format::%S</convert>
337                         </widget>
338                         <widget source="global.CurrentTime" render="Label" position="0,40" size="250,25" font="Regular;19" halign="center" valign="center" foregroundColor="#999999" transparent="1">
339                                 <convert type="ClockToText">Format:%A, %d.%m.%Y</convert>               
340                         </widget>
341                 </screen>"""
342
343         clockSkinHD = """      
344                 <screen name="ShowClock" size="280,80" zPosition="10" backgroundColor="#50202020" flags="wfNoBorder">
345                         <widget source="global.CurrentTime" render="Label" position="85,15" size="80,25" font="Regular;30" halign="left" valign="center" transparent="1">
346                                 <convert type="ClockToText">Default</convert>
347                         </widget>
348                         <widget source="global.CurrentTime" render="Label" position="162,20" size="40,18" font="Regular;24" halign="left" valign="center" transparent="1">
349                                 <convert type="ClockToText">Format::%S</convert>
350                         </widget>
351                         <widget source="global.CurrentTime" render="Label" position="0,45" size="280,30" font="Regular;23" halign="center" valign="center" foregroundColor="#999999" transparent="1">
352                                 <convert type="ClockToText">Format:%A, %d.%m.%Y</convert>               
353                         </widget>
354                 </screen>"""
355  
356         if width < 1280:
357                 if width < 1024:
358                         currentSkin = clockSkinSD
359                 else:
360                         currentSkin = clockSkinXD
361         else:           
362                 currentSkin = clockSkinHD
363                 
364         try: # try to import DateToText converter (GP3 component) to check for its existence
365                 from Components.Converter.DateToText import DateToText # change converter to obtain localized weekdays
366                 currentSkin = currentSkin.replace('<convert type="ClockToText">Format:%A, %d.%m.%Y</convert>', '<convert type="DateToText">NNNN, DD.MM.YYYY</convert>')
367         except ImportError, ie:
368                 print pluginPrintname, "DateToText converter not installed:", ie
369         return currentSkin
370         
371 ##############################################################################
372
373 def sessionstart(reason, **kwargs):
374         if reason == 0:
375                 showClock.gotSession(kwargs["session"])
376         
377 def setup(session,**kwargs):
378         try:    
379                 session.open(ShowClockSetup)
380         except:
381                 print pluginPrintname, "Pluginexecution failed"
382
383 ##############################################################################
384
385 def Plugins(**kwargs):
386         
387         if debug: print pluginPrintname, "Setting entry points"
388
389         list = [
390                 PluginDescriptor(where=[PluginDescriptor.WHERE_SESSIONSTART], fnc=sessionstart)
391                 ]
392         if config.plugins.ShowClock.menu.value == "plugin":
393                 list.append (PluginDescriptor(
394                         name = config.plugins.ShowClock.name.value + " "  + _("Ver.") + " " + VERSION, 
395                         description = config.plugins.ShowClock.description.value, 
396                         where = PluginDescriptor.WHERE_PLUGINMENU, 
397                         icon = "plugin.png", 
398                         fnc=setup)
399                 )
400         else:
401                 list.append (PluginDescriptor(
402                         name = config.plugins.ShowClock.name.value + " "  + _("Ver.") + " " + VERSION, 
403                         description = config.plugins.ShowClock.description.value, 
404                         where = PluginDescriptor.WHERE_EXTENSIONSMENU, 
405                         fnc=setup)
406                 )
407
408         return list