[MerlinSkinThemes] - fix typo reported by hawking
[enigma2-plugins.git] / merlinskinthemes / src / MerlinSkinThemes.py
1 #######################################################################
2 #
3 #  MerlinSkinThemes for Dreambox/Enigma2/Dreambox OS
4 #  Coded by marthom (c)2012 - 2019
5 #
6 #  Support: board.dreambox.tools
7 #  E-Mail: marthom@dreambox-tools.info
8 #
9 #  This plugin is open source but it is NOT free software.
10 #
11 #  This plugin may only be distributed to and executed on hardware which
12 #  is licensed by Dream Multimedia GmbH.
13 #  In other words:
14 #  It's NOT allowed to distribute any parts of this plugin or its source code in ANY way
15 #  to hardware which is NOT licensed by Dream Property.
16 #  It's NOT allowed to execute this plugin and its source code or even parts of it in ANY way
17 #  on hardware which is NOT licensed by Dream Property.
18 #
19 #  If you want to use or modify the code or parts of it,
20 #  you have to keep MY license and inform me about the modifications by mail.
21 #
22 #######################################################################
23
24 from Plugins.Plugin import PluginDescriptor
25
26 from Screens.Screen import Screen
27 from Screens.HelpMenu import HelpableScreen
28 from Screens.MessageBox import MessageBox
29 from Screens.InputBox import InputBox
30 from Screens.Standby import TryQuitMainloop
31
32 from skin import TemplatedListFonts, componentSizes
33
34 from Components.ActionMap import ActionMap, HelpableActionMap
35 from Components.Button import Button
36 from Components.Label import Label
37 from Components.Pixmap import Pixmap
38 from Components.MenuList import MenuList
39 from Components.config import config, configfile, ConfigYesNo, ConfigSubsection, getConfigListEntry, ConfigSelection, ConfigNumber, ConfigText, ConfigInteger, ConfigSubDict, ConfigBoolean
40 from Components.ConfigList import ConfigListScreen
41
42 from enigma import eListboxPythonMultiContent, gFont, RT_HALIGN_LEFT, RT_HALIGN_RIGHT, RT_VALIGN_CENTER, getEnigmaVersionString
43
44 from Tools.HardwareInfo import HardwareInfo
45 from Tools.Directories import resolveFilename, SCOPE_SKIN, SCOPE_PLUGINS, fileExists
46
47 import xml.etree.cElementTree as Tree
48
49 import shutil
50 import os
51
52 # =========================================
53 PluginVersion = "v2.7.0"
54 Title = "MerlinSkinThemes "
55 Author = "by marthom"
56 # =========================================
57
58 SkinXML = config.skin.primary_skin.value
59 SkinFile = resolveFilename(SCOPE_SKIN) + SkinXML
60 SkinName = SkinXML[0:SkinXML.find("/")]
61 ThemeFile = resolveFilename(SCOPE_SKIN) + SkinName + "/themes.xml"
62 skin_user_xml = "/etc/enigma2/skin_user.xml"
63 enigmacontrol = "/var/lib/opkg/info/enigma2.control"
64 merlinChk = "/usr/share/enigma2/merlin_setup.xml"
65 GP3Chk = "/usr/lib/enigma2/python/Plugins/Bp/geminimain/gVersion.py"
66 GP4Chk = "/usr/lib/enigma2/python/Plugins/GP4/geminilocale/gVersion.py"
67 ImageCreater = "/usr/lib/enigma2/python/Components/ImageCreater.py"
68 PIL = "/usr/lib/python2.7/site-packages/PIL/Image.py"
69
70 # Liste der Vorschaubilder
71 myList = ["InfoBar", "Menu", "PluginBrowser", "ChannelSelection", "MovieSelection", "MoviePlayer", "SecondInfoBar", "GraphMultiEPG", "MessageBox", "InputBox", "ChoiceBox", "Mute", "Volume", "MerlinMusicPlayer2", "ExtLCDInfoBar", "ExtLCDEventView", "ExtLCDStandby", "ExtLCDMoviePlayer", "ExtLCDMMP2", "OLEDInfoBar", "OLEDEventView", "OLEDStandby", "OLEDMoviePlayer", "OLEDMMP2", "LCDInfoBar", "LCDEventView", "LCDStandby", "LCDMoviePlayer", "LCDMMP2"]
72
73 # Enigma2Version
74 E2ver = _("not available")
75 if open("/proc/stb/info/model","rb").read() == "dm7080":
76         if fileExists(enigmacontrol):
77                 file = open(enigmacontrol, 'r')
78                 while 1:
79                         line = file.readline()
80                         if not line:break
81                         if line[:9] == "Version: ":
82                                 E2ver = line[9:-1]
83                 file.close()
84 else:
85         E2ver = getEnigmaVersionString()
86
87 # Merlin
88 Merlin = False
89 if fileExists(merlinChk):
90         Merlin = True
91
92 # GP3
93 GP3 = False
94 GP3ver = ""
95 if fileExists(GP3Chk):
96         GP3 = True
97         file = open(GP3Chk, 'r')
98         data = ""
99         while 1:
100                 line = file.readline()
101                 if not line:break
102                 data += line
103         file.close()
104         
105         data = data.split("'")
106         GP3ver = data[1]
107
108 # GP4
109 GP4 = False
110 GP4ver = ""
111 if fileExists(GP4Chk):
112         GP4 = True
113         file = open(GP4Chk, 'r')
114         data = ""
115         while 1:
116                 line = file.readline()
117                 if not line:break
118                 data += line
119         file.close()
120         
121         data = data.split("'")
122         GP4ver = data[1]
123
124 # Arm/mipsel/aarch64
125 ArchArm = False
126 Arch64 = False
127 ArchMipsel = False
128 if HardwareInfo().get_device_name() in ('dm900', 'dm920'):
129         ArchArm = True
130         ArchString = "ARM"
131         IdString = "3"
132         DisplayXY = "400x240"
133 elif HardwareInfo().get_device_name() in ('one', 'two'):
134         Arch64 = True
135         ArchString = "AARCH64"
136         IdString = "0" #no display
137         DisplayXY = "0x0"
138 else:
139         if HardwareInfo().get_device_name() == 'dm820':
140                 IdString = "2"
141                 DisplayXY = "96x64"
142         elif HardwareInfo().get_device_name() == 'dm7080':
143                 IdString = "1"
144                 DisplayXY = "132x64"
145         ArchMipsel = True
146         ArchString = "MIPSEL"
147 ModelString = HardwareInfo().get_device_name().upper()
148 displayDict = {"1": "lcdscreenthemes", "2": "oldescreenthemes", "3": "extlcdscreenthemes"}
149 displayTag = displayDict[IdString]
150
151 print "------------------------------------------------"
152 print HardwareInfo().get_device_name()
153 print PluginVersion
154 print "------------------------------------------------"
155
156 # skin_user.xml
157 SkinUser = False
158 if fileExists(skin_user_xml):
159         SkinUser = True
160         
161 # Config
162 config.plugins.MerlinSkinThemes = ConfigSubsection()
163 config.plugins.MerlinSkinThemes.Skin = ConfigText(default=SkinName)
164 config.plugins.MerlinSkinThemes.selSkin = ConfigText(default=SkinName)
165 config.plugins.MerlinSkinThemes.ShowPrevPNG = ConfigText(default="1")
166 config.plugins.MerlinSkinThemes.CornerRadius = ConfigText(default="")
167 config.plugins.MerlinSkinThemes.applied = ConfigBoolean(default=False)
168
169 def initConfigSubDict(sectionName=None):
170         if sectionName == "Design":
171                 config.plugins.MerlinSkinThemes.Designs = ConfigSubDict()
172         elif sectionName == "Themes":
173                 config.plugins.MerlinSkinThemes.Themes = ConfigSubDict()
174         elif sectionName == "Screens":
175                 config.plugins.MerlinSkinThemes.Screens = ConfigSubDict()
176         elif sectionName == "DisplayScreens":
177                 config.plugins.MerlinSkinThemes.DisplayScreens = ConfigSubDict()                
178
179 # list of display screens (a.k.a. summaries)
180 displayScreenList = ["InfoBarSummary", "EventView_summary", "StandbySummary", "InfoBarMoviePlayerSummary", "MerlinMusicPlayer2LCDScreen"]
181 # list of screens
182 screenList = ["InfoBar", "Menu", "PluginBrowser", "ChannelSelection", "MovieSelection", "MoviePlayer", "SecondInfoBar", "GraphMultiEPG", "EventView", "EPGSelection", "MessageBox", "InputBox", "ChoiceBox", "Mute", "Volume", "MerlinMusicPlayer2Screen", "MerlinMusicPlayer2Screen_%s" %(ArchString), "MerlinMusicPlayer2ScreenSaver", "MerlinMusicPlayer2ScreenSaver_%s" %(ArchString)]
183 # list of themes
184 themeList = ["ColorTheme", "SkinPathTheme", "FontTheme",  "BorderSetTheme", "WindowStyleScrollbarTheme", "ComponentTheme", "LayoutTheme", "GlobalsTheme", "PNGTheme" ]
185
186 # shared functions
187 # ImageCreator
188 import Image
189
190 class ImageCreator:
191         def __init__(self):
192                 pass
193
194         def createRectangle(self, width, height, color, filename):
195                 image = Image.new(mode='RGBA',size=(width,height),color=color)
196                 image.save(filename)
197
198 imageCreator = ImageCreator()
199
200 def hex2argb(value):
201         value = value.lstrip('#')
202         lv = len(value)
203         return tuple(int(value[i:i+lv/4], 16) for i in range(0, lv, lv/4))
204         
205 def XMLindent(elem, level):
206         i = "\n" + (level*"    ")
207         #a = "\n%%-%ds" % level
208         #i = a % '  '
209                 
210         if len(elem):
211                 if not elem.text or not elem.text.strip():
212                         elem.text = i + "    "
213                 if not elem.tail or not elem.tail.strip():
214                         elem.tail = i
215                 for elem in elem:
216                         XMLindent(elem, level+1)
217                 if not elem.tail or not elem.tail.strip():
218                         elem.tail = i
219         else:
220                 if level and (not elem.tail or not elem.tail.strip()):
221                         elem.tail = i
222
223 import datetime
224
225 def setThemes(themeFile=None, skinFile=None, configDict=None):
226         # set all "inactive", set new theme "active"
227         curTheme = Tree.parse(themeFile)
228         rootTheme = curTheme.getroot()
229
230         curSkin = Tree.parse(skinFile)
231         rootSkin = curSkin.getroot()
232
233         if rootSkin.find("merlinskinthemes") is None:
234                 mst = Tree.Element("merlinskinthemes", {"text":"Edited with MerlinSkinThemes"})
235                 rootSkin.insert(0, mst)
236
237         for theme in [("colortheme", "colors", "color"), ("fonttheme", "fonts", "font"), ("layouttheme", "layouts", "layout"), ("globalstheme", "globals", ""), ("bordersettheme", "", "borderset"), ("windowstylescrollbartheme", "", ""), ("componenttheme", "components", ""),("pngtheme", "", "")]:
238                 #find colortheme in themes.xml
239                 if rootTheme.find(theme[0]) is not None:
240                         # loop themes in selected theme
241                         for currenttheme in rootTheme.findall(theme[0]):
242                                 attributeDict = {}
243                                 # find selected theme
244                                 if configDict is None:
245                                         currentValue = config.plugins.MerlinSkinThemes.Themes[theme[0]].value
246                                 else:
247                                         currentValue = configDict.get("config.plugins.MerlinSkinThemes.Themes.%s" %(theme[0]), None)
248                                 if currenttheme.get("name") == currentValue:
249                                         # set theme active
250                                         currenttheme.set("value", "active")
251                                         # find all in skin.xml
252                                         if (theme[1] != "" and theme[2] != ""):
253                                                 skinElement = rootSkin.find(theme[1])
254                                                 # delete all in skin.xml
255                                                 if theme[1] != "layouts" and theme[1] != "components":
256                                                         for element in skinElement.findall(theme[2]):
257                                                                 skinElement.remove(element)
258                                         if theme[1] != "":                              
259                                                 # find all in themes.xml
260                                                 themeElement = currenttheme.find(theme[1])
261                                         # add all elements from themes.xml to skin.xml
262                                         if themeElement is not None:
263                                                 if theme[1] in ["layouts","components","globals"]:
264                                                         skinElement = rootSkin.find(theme[1])
265                                                         rootSkin.remove(skinElement)
266                                                         rootSkin.append(Tree.fromstring(Tree.tostring(themeElement)))
267                                                 elif theme[2] != "":
268                                                         for childElement in themeElement.findall(theme[2]):
269                                                                 if theme[0] in ["colortheme", "fonttheme"]:
270                                                                         name = childElement.get("name", None)
271                                                                         if name is not None:
272                                                                                 attributeDict["name"] = name
273                                                                         value = childElement.get("value", None)
274                                                                         if value is not None:
275                                                                                 attributeDict["value"] = value
276                                                                         filename = childElement.get("filename", None)
277                                                                         if filename is not None:
278                                                                                 attributeDict["filename"] = filename
279                                                                         scale = childElement.get("scale", None)
280                                                                         if scale is None and childElement == "font":
281                                                                                 scale = "100"
282                                                                         if scale is not None:
283                                                                                 attributeDict["scale"] = scale
284                                                                         replacement = childElement.get("replacement", None)
285                                                                         if replacement is None and childElement == "font":
286                                                                                 replacement = "0"
287                                                                         if replacement is not None:
288                                                                                 attributeDict["replacement"] = replacement
289                                                 
290                                                                         Tree.SubElement(skinElement, theme[2], attributeDict)
291                                         if theme[0] == "bordersettheme":
292                                                 ws = rootSkin.find("windowstyle")
293                                                 if ws.get("id") == "0":
294                                                         for bs in ws.findall(theme[2]):
295                                                                 if bs.get("name") == "bsWindow":
296                                                                         for px in bs.findall("pixmap"):
297                                                                                 bs.remove(px)
298                                                                                         
299                                                                         for tbs in currenttheme.findall(theme[2]):
300                                                                                 if tbs.get("name") == "bsWindow":
301                                                                                         for tpx in tbs.findall("pixmap"):
302                                                                                                 bs.append(Tree.fromstring(Tree.tostring(tpx)))
303                                                                 if bs.get("name") == "bsListboxEntry":
304                                                                         for px in bs.findall("pixmap"):
305                                                                                 bs.remove(px)
306                                         
307                                                                         for tbs in currenttheme.findall(theme[2]):
308                                                                                 if tbs.get("name") == "bsListboxEntry":
309                                                                                         for tpx in tbs.findall("pixmap"):
310                                                                                                 bs.append(Tree.fromstring(Tree.tostring(tpx)))
311                                         if theme[0] == "windowstylescrollbartheme":
312                                                 for wssb in rootSkin.findall("windowstylescrollbar"):
313                                                         if wssb.get("id") == "4":
314                                                                 for all in wssb.findall("*"):
315                                                                         wssb.remove(all)
316                                                         
317                                                                 for tall in currenttheme.findall("*"):
318                                                                         wssb.append(Tree.fromstring(Tree.tostring(tall)))       
319                                         if theme[0] == "pngtheme":
320                                                 for tp in currenttheme.findall("png"):
321                                                         png_name = tp.get("name")
322                                                         png_width = int(tp.get("width"))
323                                                         png_height = int(tp.get("height"))
324                                                         png_argb = tp.get("argb")
325                                                         acolor = hex2argb(png_argb)
326                                                 
327                                                         if png_name is not None and png_width is not None and png_height is not None and png_argb is not None:
328                                                                 imageCreator.createRectangle(png_width, png_height, (acolor[1], acolor[2], acolor[3], acolor[0]), resolveFilename(SCOPE_SKIN) + SkinName + "/" + png_name) 
329                                                                                                         
330                                 # if name does not match set it to inactive     
331                                 else:
332                                         currenttheme.set("value", "inactive")
333
334         if rootTheme.find("screenthemes") is not None:
335                 themes = rootTheme.find("screenthemes")
336                 for screens in themes.findall("screens"):
337                         for screenname in screenList:
338                                 if screens.get("name") == screenname:
339                                         for screen in screens.findall("screentheme"):
340                                                 if configDict is None:
341                                                         currentValue = config.plugins.MerlinSkinThemes.Screens[screenname].value
342                                                 else:
343                                                         currentValue = configDict.get("config.plugins.MerlinSkinThemes.Screens.%s" %(screenname),None)
344                                                 if screen.get("name") == currentValue:
345                                                         screen.set("value", "active")
346                                                         newscreen = screen.find("screen")
347
348                                                         # delete old screen
349                                                         for SkinScreen in rootSkin.findall("screen"):
350                                                                 if SkinScreen.get("name") == screenname:
351                                                                         rootSkin.remove(SkinScreen)
352                                                         
353                                                         # Set new screen
354                                                         rootSkin.append(Tree.fromstring(Tree.tostring(newscreen)))
355                                                                         
356                                                 else:
357                                                         screen.set("value", "inactive")
358
359         # LCD / OLED / External LCD
360         if rootTheme.find(displayTag) is not None:
361                 themes = rootTheme.find(displayTag)
362                 for screens in themes.findall("screens"):
363                         for displayscreenname in displayScreenList:
364                                 if screens.get("name") == displayscreenname:
365                                         for screen in screens.findall(displayTag[:-1]):
366                                                 if configDict is None:
367                                                         currentValue = config.plugins.MerlinSkinThemes.DisplayScreens[displayscreenname].value
368                                                 else:
369                                                         currentValue = configDict.get("config.plugins.MerlinSkinThemes.DisplayScreens.%s" %(displayscreenname), None)
370                                                 if screen.get("name") == currentValue:
371                                                         screen.set("value", "active")
372                                                         newscreen = screen.find("screen")
373
374                                                         # delete old screen
375                                                         for SkinScreen in rootSkin.findall("screen"):
376                                                                 if SkinScreen.get("name") == displayscreenname and SkinScreen.get("id") == IdString:
377                                                                         rootSkin.remove(SkinScreen)
378                                                         
379                                                         # Set new screen
380                                                         rootSkin.append(Tree.fromstring(Tree.tostring(newscreen)))
381                                                                 
382                                                 else:
383                                                         screen.set("value", "inactive")
384
385         # corner Radius in skin.xml in allen eLabel ersetzen
386         if config.plugins.MerlinSkinThemes.CornerRadius.value <> "":
387                 for elabel in rootSkin.findall('.//eLabel[@cornerRadius]'):
388                         if 'cornerRadius' in elabel.attrib:
389                                 if rootTheme.find("cornerradius") is not None:
390                                         crtheme = rootTheme.find("cornerradius")
391                                         
392                                         if elabel.get("cornerRadius") <> crtheme.get("exclude"):
393                                                 elabel.set("cornerRadius", config.plugins.MerlinSkinThemes.CornerRadius.value)
394                                                         
395                                                 for r in crtheme.findall("radius"):
396                                                         if r.get("name") == config.plugins.MerlinSkinThemes.CornerRadius.value:
397                                                                 r.set("value", "active")
398                                                         else:
399                                                                 r.set("value", "inactive")
400
401         XMLindent(rootSkin, 0)
402         curSkin.write(skinFile)
403
404         # SkinPathTheme
405         xmlTree = Tree.parse(skinFile)
406         xmlRoot = xmlTree.getroot()
407         xmlString = Tree.tostring(xmlRoot)
408
409         if rootTheme.find("skinpaththemes") is not None:
410                 spt = rootTheme.find("skinpaththemes")
411                 for theme in spt.findall("theme"):
412                         if configDict is None:
413                                 currentValue = config.plugins.MerlinSkinThemes.Themes["skinpaththeme"].value
414                         else:
415                                 currentValue = configDict.get("config.plugins.MerlinSkinThemes.Themes.%s" %(skinpaththeme), None)
416                         if theme.get("name") == currentValue:
417                                 newPath = theme.get("path")
418                                 theme.set("value", "active")
419                         else:
420                                 theme.set("value", "inactive")
421                                         
422                 for theme in spt.findall("theme"):
423                         xmlString = xmlString.replace(theme.get("path"), newPath)
424                 
425                 xmlSkin = open(skinFile, "w")
426                 xmlSkin.write(xmlString)
427                 xmlSkin.close()
428
429         curTheme.write(themeFile)
430
431 class MerlinSkinThemes(Screen, HelpableScreen, ConfigListScreen):
432         skin = """
433                 <screen position="center,center" size="1920,1080" title="%s" backgroundColor="#00808080" >
434                         <widget name="DescLabel" position="10,10" size="1900,40" font="Regular;26" zPosition="2" valign="center" halign="center" />
435
436                         <widget name="ListLabel" position="10,60" size="945,40" font="Regular;26" zPosition="2" valign="center" halign="left" />
437                         <widget name="ImageInfo" position="965,60" size="945,40" font="Regular;26" zPosition="2" halign="left" />
438                         
439                         <widget name="SkinsList" position="10,110" size="945,910" scrollbarMode="showOnDemand" zPosition="1" />
440                         <widget name="config" position="10,110" size="945,910" scrollbarMode="showOnDemand" zPosition="1" /> 
441
442                         <widget name="SkinCopyright" position="965,110" size="945,200" font="Regular;18" zPosition="2" halign="left" />
443                         <widget name="Preview" position="965,320" size="945,700" alphatest="blend" />
444                         
445                         <widget name="key_red" position="10,1030" size="200,40" valign="center" halign="center" zPosition="3" transparent="1" font="Regular;24" />
446                         <widget name="key_green" position="258,1030" size="200,40" valign="center" halign="center" zPosition="3" transparent="1" font="Regular;24" />
447                         <widget name="key_yellow" position="506,1030" size="200,40" valign="center" halign="center" zPosition="3" transparent="1" font="Regular;24" />
448                         <widget name="key_blue" position="755,1030" size="200,40" valign="center" halign="center" zPosition="3" transparent="1" font="Regular;24" />
449
450                         <ePixmap name="red" position="10,1030" zPosition="1" size="200,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="blend" />
451                         <ePixmap name="green" position="258,1030" zPosition="1" size="200,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="blend" />
452                         <ePixmap name="yellow" position="506,1030" zPosition="1" size="200,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="blend" />
453                         <ePixmap name="blue" position="755,1030" zPosition="1" size="200,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="blend" />
454                 </screen>"""% ("MerlinSkinThemes")
455
456         ThemeName = ""
457         selSkinName = ""
458         selThemeFile = ""
459         
460         def __init__(self, session):
461                 print "[MST] " + PluginVersion + " running..."
462                 
463                 self.session = session
464                 
465                 Screen.__init__(self, session)
466                 HelpableScreen.__init__(self)
467                 
468                 self.clist = []
469                 ConfigListScreen.__init__(self, self.clist)
470                 
471                 self.setTitle(Title + " " + PluginVersion + " - " + Author)
472
473                 if not SkinUser:
474                         self["ListLabel"] = Label(_("Skinlist") )
475                 else:
476                         self["ListLabel"] = Label(_("Skinlist") + " - ATTENTION: skin_user.xml found!!!")
477                 
478                 self["DescLabel"] = Label(Title + " " + PluginVersion + " " + Author)
479                 self["SkinCopyright"] = Label()
480                 self["Preview"] = Pixmap()
481                 self["ImageInfo"] = Label()
482                 
483                 self.curList = "SkinsList"
484                 
485                 self["key_red"] = Button(_("exit"))
486                 self["key_green"] = Button(_("switch to skin"))
487                 self["key_yellow"] = Button(_("save as design"))
488                 self["key_blue"] = Button(" ")
489                 
490                 self.skinsList = []
491                 self["SkinsList"] = GetSkinsList([])
492
493                 self.onSelectionChanged = [ ]
494                 
495                 self["ColorActions"] = HelpableActionMap(self, "ColorActions",
496                 {
497                         "red":     self.buttonRed,
498                         "green":   self.buttonGreen,
499                         "yellow":  self.buttonYellow,
500                 }, -1)
501                 
502                 self["DirectionActions"] = HelpableActionMap(self, "DirectionActions",
503                 {
504                         "up":           (self.up, _("Move cursor up")),
505                         "down":         (self.down, _("Move cursor down")),
506                         "left":         (self.left, _("Move cursor left")),
507                         "right":        (self.right, _("Move cursor right")),
508                 }, -1)
509
510                 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
511                 {
512                         "ok":           (self.ok, ""),
513                         "cancel":       (self.exit, _("Close plugin")),
514                 }, -1)
515
516                 self["TeleTextActions"] = HelpableActionMap(self, "TeleTextActions",
517                 {
518                         "help":         (self.Help, ""),
519                         "info":         (self.Info, ""),
520                 }, -1)
521
522                 self["MenuActions"] = HelpableActionMap(self, "MenuActions",
523                 {
524                         "menu":         (self.MSTMenu, ""),
525                 }, -1)
526                 
527                 self.updateSkinList()
528                 
529                 MerlinSkinThemes.selSkinName = self["SkinsList"].getCurrent()[1][7]
530                 MerlinSkinThemes.selSkinFile = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/skin.xml"
531                 MerlinSkinThemes.selThemeFile = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/themes.xml"
532                 
533                 self.onLayoutFinish.append(self.startRun)
534
535         def startRun(self):
536                 self["SkinsList"].onSelectionChanged.append(self.changedSkinsList)
537
538                 MerlinSkinThemes.selSkinName = self["SkinsList"].getCurrent()[1][7]
539                 MerlinSkinThemes.selSkinFile = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/skin.xml"
540                 MerlinSkinThemes.selThemeFile = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/themes.xml"
541                 
542                 self["config"].hide()
543                 
544                 self["SkinsList"].moveToIndex(self["SkinsList"].selectedIndex)
545
546                 self.ImageInfo()
547                 if fileExists(MerlinSkinThemes.selSkinFile):
548                         self.CopyrightInfo()
549
550         # parse themes.xml
551         def readThemes(self):
552                 self.clist = []
553
554                 try:
555                         xml = Tree.parse(MerlinSkinThemes.selThemeFile)
556
557                         selSkinList = []
558                         selSkinList.append(MerlinSkinThemes.selSkinName)
559                         config.plugins.MerlinSkinThemes.selSkin = MyConfigSelection(default=MerlinSkinThemes.selSkinName, choices = selSkinList)
560                         self.clist.append(getConfigListEntry(" ", ))
561                         self.clist.append(getConfigListEntry("Skin", config.plugins.MerlinSkinThemes.selSkin))
562                         
563                         #####################
564                         #       -- Designs --   #
565                         #####################
566                         #       <designs>
567                         #               <design>
568                         #                       <xyzTheme />
569                         #               </design>
570                         #       </designs>
571                         # this reads all <design> and its themes that are defined in <designs>
572                         # name of <design> is read and displayed in the section DESIGNS, active one is set as default
573                         self.clist.append(getConfigListEntry(" ", ))
574                         self.clist.append(getConfigListEntry(" " + u'\u00b7' + " DESIGNS", ))
575         
576                         if xml.find("designs") is not None:
577                                 initDesignsDone = False
578                                 ds = xml.find("designs")
579                                 for element in ["design"]:
580                                         elementList = []
581                                         elementList.append("-none-")
582                                         defaultValue = "-none-"
583                                         for design in ds.findall(element):
584                                                 elementList.append(design.get("name"))
585                                                 #if design.get("value") == "active":
586                                                         #defaultValue = design.get("name")
587
588                                 if len(elementList) > 0:
589                                         if not initDesignsDone:
590                                                 initConfigSubDict("Design")
591                                                 initDesignsDone = True
592                                         config.plugins.MerlinSkinThemes.Designs[element] = MyConfigSelection(default=defaultValue, choices = elementList)
593                                         self.clist.append(getConfigListEntry("Design", config.plugins.MerlinSkinThemes.Designs[element]))
594
595                         ################
596                         # -- Themes -- #
597                         ################
598                         # name of theme is read and displayed in the section THEMES, active one is set as default
599                         self.clist.append(getConfigListEntry(" ", ))
600                         self.clist.append(getConfigListEntry(" " + u'\u00b7' + " THEMES", ))
601                         
602                         themesInitDone = False
603                         for element in themeList:
604                                 elementList = []
605                                 defaultValue = None
606                                 if xml.find(element.lower()) is not None:
607                                         for theme in xml.findall(element.lower()):
608                                                 elementList.append(theme.get("name"))
609                                                 if theme.get("value") == "active":
610                                                         defaultValue = theme.get("name")
611                                 
612                                 if len(elementList) > 0:
613                                         if not themesInitDone:
614                                                 initConfigSubDict("Themes")
615                                                 themesInitDone = True
616                                         config.plugins.MerlinSkinThemes.Themes[element.lower()] = MyConfigSelection(default=defaultValue, choices = elementList)
617                                         self.clist.append(getConfigListEntry(element, config.plugins.MerlinSkinThemes.Themes[element.lower()]))
618                         
619                         #################
620                         # -- SCREENS -- #
621                         #################
622                         #       <screenthemes>
623                         #               <!-- multiple screens possible -->
624                         #               <screens name="screenname">
625                         #                       <!-- multiple screentheme possible -->
626                         #                       <screentheme>
627                         #                               <screen>...</screen>
628                         #                       </screentheme>
629                         #               </screens>
630                         #       </screenthemes>
631                         self.clist.append(getConfigListEntry(" ", ))
632                         self.clist.append(getConfigListEntry(" " + u'\u00b7' + " SCREENS", ))
633
634                         if xml.find("screenthemes") is not None:
635                                 st = xml.find("screenthemes")
636                                 initScreenDone = False
637                                 for screens in st.findall("screens"):
638                                         for screenname in screenList:
639                                                 elementList = []
640                                                 defaultValue = None
641                                                 if screens.get("name") == screenname:
642                                                         for themes in screens.findall("screentheme"):
643                                                                 elementList.append(themes.get("name"))
644                                                                 if themes.get("value") == "active":
645                                                                         defaultValue = themes.get("name")
646                                                         if len(elementList)>0:
647                                                                 if not initScreenDone:
648                                                                         initConfigSubDict("Screens")
649                                                                         initScreenDone = True
650                                                                 config.plugins.MerlinSkinThemes.Screens[screenname] = MyConfigSelection(default=defaultValue, choices = elementList)
651                                                                 self.clist.append(getConfigListEntry(screenname, config.plugins.MerlinSkinThemes.Screens[screenname]))
652
653                         #########################
654                         # -- Display Screens -- #
655                         #########################
656                         #       <lcdscreenthemes> / <oledscreenthemes> / <extlcdscreenthemes>
657                         #               <!-- multiple screens possible -->
658                         #               <screens name="screenname">
659                         #                       <!-- multiple lcdscreentheme possible -->
660                         #                       <lcdscreentheme> / <oledscreentheme> / <extlcdscreentheme>
661                         #                               <screen>...</screen>
662                         #                       </lcdscreentheme> / </oledscreentheme> / </extlcdscreentheme>
663                         #               </screens>
664                         #       </lcdscreenthemes> / <oledscreenthemes> / </extlcdscreenthemes>
665                                                 
666                         if xml.find(displayTag) is not None:
667                                 self.clist.append(getConfigListEntry(" ", ))
668                                 self.clist.append(getConfigListEntry(" " + u'\u00b7' + " DISPLAY SCREENS ID=%s (%s) %s" %(IdString, ModelString, DisplayXY ), ))                
669                 
670                                 initDisplayScreenDone = False
671                                 for element in displayScreenList:
672                                         elementList = []
673                                         defaultValue = None
674                                         st = xml.find(displayTag)
675                                         if st.find("screens[@name='%s']" %(element)) is not None:
676                                                 lst = st.find("screens[@name='%s']" %(element))
677                                                 for th in lst.findall(displayTag[:-1]):
678                                                         for screen in th.findall("screen"):
679                                                                 if screen.get("name") == element and screen.get("id") == IdString:
680                                                                         elementList.append(th.get("name"))
681                                                                         if th.get("value") == "active":
682                                                                                 defaultValue = th.get("name")
683                                                                                 
684                                                 if len(elementList) > 0:
685                                                         if not initDisplayScreenDone:
686                                                                 initConfigSubDict("DisplayScreens")
687                                                                 initDisplayScreenDone = True
688                                                         config.plugins.MerlinSkinThemes.DisplayScreens[element] = MyConfigSelection(default=defaultValue, choices = elementList)
689                                                         self.clist.append(getConfigListEntry(element, config.plugins.MerlinSkinThemes.DisplayScreens[element]))
690                         
691                         ######################  
692                         # -- cornerRadius -- #
693                         ######################
694                         #       <cornerradius>
695                         #               <radius />
696                         #       </cornerradius>
697                         if xml.find("cornerradius") is not None:
698                                 self.clist.append(getConfigListEntry(" ", ))
699                                 self.clist.append(getConfigListEntry(" " + u'\u00b7' + " CORNERRADIUS", ))
700
701                                 elementList = []
702                                 defaultValue = None
703                                 cr = xml.find("cornerradius")
704                                 for cradius in cr.findall("radius"):
705                                         elementList.append(cradius.get("name"))
706                                         if cradius.get("value") == "active":
707                                                 defaultValue = cradius.get("name")
708
709                                 if len(elementList) > 0:
710                                         config.plugins.MerlinSkinThemes.CornerRadius = MyConfigSelection(default=defaultValue, choices = elementList)
711                                         self.clist.append(getConfigListEntry("CornerRadius", config.plugins.MerlinSkinThemes.CornerRadius))
712                                                 
713                 except Exception as error:
714                         print "Error", error
715                         print "[MST] themes.xml in " + MerlinSkinThemes.selSkinName + " corrupt!"
716                         self.clist.append(getConfigListEntry(" ", ))
717                         self.clist.append(getConfigListEntry(_(">>> ERROR - themes.xml in " + MerlinSkinThemes.selSkinName + " corrupt! <<<"), ))
718                         
719                 self["config"].setList(self.clist)
720                 
721         def buttonGreen(self):
722                 if self.curList == "SkinsList":
723                         # set new skin
724                         sel = self["SkinsList"].getCurrent()
725                         if sel[1][7] == "Default Skin":
726                                 skinfile = "skin.xml"
727                         else:
728                                 skinfile = "%s/skin.xml" % sel[1][7]
729
730                         # Dr. Best Infobar position
731                         if fileExists("/usr/share/enigma2/merlin_setup.xml"):
732                                 config.merlin2.infobar_position_offset_x.value = 0
733                                 config.merlin2.infobar_position_offset_x.save()
734                                 config.merlin2.infobar_position_offset_y.value = 0
735                                 config.merlin2.infobar_position_offset_y.save()
736                                 config.merlin2.movieplayer_infobar_position_offset_x.value = 0
737                                 config.merlin2.movieplayer_infobar_position_offset_x.save()
738                                 config.merlin2.movieplayer_infobar_position_offset_y.value = 0
739                                 config.merlin2.movieplayer_infobar_position_offset_y.save()
740                                 
741                         config.skin.primary_skin.value = skinfile
742                         config.skin.primary_skin.save()
743                         restartbox = self.session.openWithCallback(self.restartGUI,MessageBox,_("GUI needs a restart to apply a new skin\nDo you want to Restart the GUI now?"), MessageBox.TYPE_YESNO)
744                         restartbox.setTitle(_("Restart GUI now?"))
745                 elif self.curList == "ConfigList":
746                         askBox = self.session.openWithCallback(self.askYN,MessageBox,_("[apply themes] needs time to build new settings\nDo you want to do this now?"), MessageBox.TYPE_YESNO)
747                         askBox.setTitle(_("Apply themes now?"))
748
749         def askYN(self, answer):
750                 if answer is True:
751                         setThemes(MerlinSkinThemes.selThemeFile, MerlinSkinThemes.selSkinFile, None)
752                         config.plugins.MerlinSkinThemes.applied.value = True
753                         config.plugins.MerlinSkinThemes.applied.save()
754                         for x in self["config"].list:
755                                 if len(x) > 1:
756                                         x[1].save()
757                         configfile.save()
758                         if SkinName == MerlinSkinThemes.selSkinName:
759                                 restartbox = self.session.openWithCallback(self.restartGUI,MessageBox,_("GUI needs a restart to apply a new skin\nDo you want to Restart the GUI now?"), MessageBox.TYPE_YESNO)
760                                 restartbox.setTitle(_("Restart GUI now?"))
761                         
762                         else:
763                                 self.session.open(MessageBox, _("Changes to skin " + MerlinSkinThemes.selSkinName + " ready!"), MessageBox.TYPE_INFO)
764
765         def MSTScrFix(self, answer):
766                 if answer is True:
767                         curSkin = Tree.parse(MerlinSkinThemes.selSkinFile)
768                         rootSkin = curSkin.getroot()
769                         mstscreen = rootSkin.find("screen[@name='MerlinSkinThemes']")
770                         rootSkin.remove(mstscreen)
771
772                         XMLindent(rootSkin, 0)
773                         curSkin.write(MerlinSkinThemes.selSkinFile)
774                         
775                         self.updateSkinList()
776
777                         self.session.open(MessageBox, '<screen name="MerlinSkinThemes"...> was removed from selected skin.', MessageBox.TYPE_INFO)
778                         
779         def buttonRed(self):
780                 self.exit()
781                 
782         def buttonYellow(self):
783                 if self.curList == "SkinsList":
784                         if self["SkinsList"].getCurrent()[3][7] == _("no themes.xml"):
785                                 self.createThemes()
786
787                         if self["SkinsList"].getCurrent()[3][7] == _("no skin.xml"):
788                                 self.delSkinDir()
789                                 
790                 elif self.curList == "ConfigList":
791                         if self["config"].getCurrent()[0] == "Design":
792                                 # delete design
793                                 self.deleteDesign()
794                         
795                         else:
796                                 # save as design
797                                 self.session.openWithCallback(self.saveDesign, InputBox, title=_("Please enter designname!"))
798         
799         # write a new design into <designs>     
800         def saveDesign(self, designname):
801                 if designname is not None:
802                 
803                         designname = designname.strip()
804                         
805                         curTree = Tree.parse(MerlinSkinThemes.selThemeFile)
806                         xmlroot = curTree.getroot()
807                         
808                         if xmlroot.find("designs") is None:
809                                 xmldesigns = Tree.SubElement(xmlroot, "designs")
810                         else:
811                                 xmldesigns = xmlroot.find("designs")
812
813                         # check if design exists
814                         if xmldesigns.find("design[@name='" + designname + "']") is not None:
815                                 xmldesigns.remove(xmldesigns.find("design[@name='" + designname + "']"))
816                                 
817                         # write design
818                         xmldesign = Tree.SubElement(xmldesigns, "design", {"name": designname, "value": "active"})
819                         
820                         for element in themeList:
821                                 # remark: for now don't handle it here. Needs alignment
822                                 if element == "SkinPathTheme":
823                                         continue
824                                 # check if theme exists
825                                 if element.lower() in config.plugins.MerlinSkinThemes.Themes.keys():
826                                         if xmlroot.find("%s[@name='" %(element.lower()) + config.plugins.MerlinSkinThemes.Themes[element.lower()].value + "']" ) is not None:
827                                                 if xmldesign.find(element) is not None:
828                                                         td = xmldesign.find(element)
829                                                         td.set("name", config.plugins.MerlinSkinThemes.Themes[element.lower()].value)
830                                                 else:
831                                                         Tree.SubElement(xmldesign, element, {"name": config.plugins.MerlinSkinThemes.Themes[element.lower()].value })
832
833                         # SkinPathThemes
834                         # todo: same check required like for themes? is it really possible to define it in Designs?
835                         if xmlroot.find("skinpaththemes") is not None:
836                                 t = xmlroot.find("skinpaththemes")
837                                 
838                                 if t.find("theme[@name='" + config.plugins.MerlinSkinThemes.Themes["skinpaththemes"].value + "']") is not None:
839                                         if xmldesign.find("SkinPathTheme") is not None:
840                                                 td = xmldesign.find("SkinPathTheme")
841                                                 td.set("name", config.plugins.MerlinSkinThemes.Themes["skinpaththemes"].value)
842                                         else:
843                                                 Tree.SubElement(xmldesign, "SkinPathTheme", {"name": config.plugins.MerlinSkinThemes.Themes["skinpaththemes"].value})
844                                         
845                         # Screens
846                         if xmlroot.find("screenthemes") is not None:
847                                 t = xmlroot.find("screenthemes")
848                                 
849                                 for element in screenList:
850                                         if t.find("screens[@name='%s']" %(element)) is not None:
851                                                 ts = t.find("screens[@name='%s']" %(element))
852                                                 if ts.find("screentheme[@name='" + config.plugins.MerlinSkinThemes.Screens[element].value + "']") is not None:
853                                                         Tree.SubElement(xmldesign, element, {"name": config.plugins.MerlinSkinThemes.Screens[element].value})
854                                 
855                         # LCD Screens
856                         if xmlroot.find(displayTag) is not None:
857                                 t = xmlroot.find(displayTag) 
858                                 
859                                 for element in displayScreenList:
860                                         if t.find("screens[@name='%s']" %(element)) is not None:
861                                                 ts = t.find("screens[@name='%s']" %(element))
862                                                 if ts.find("%s[@name='" %(displayTag[:-1]) + config.plugins.MerlinSkinThemes.DisplayScreens[element].value + "']") is not None:
863                                                 # todo: LCDInfoBar vs. InfoBarSummary!!!! wie geht das?
864                                                         Tree.SubElement(xmldesign, element, {"name": config.plugins.MerlinSkinThemes.DisplayScreens[element].value})
865                         
866                         # cornerRadius
867                         if xmlroot.find("cornerradius") is not None:
868                                 if xmldesign.find("CornerRadius") is not None:
869                                         td = xmldesign.find("CornerRadius")
870                                         td.set("name", config.plugins.MerlinSkinThemes.CornerRadius.value)
871                                 else:
872                                         Tree.SubElement(xmldesign, "CornerRadius", {"name": config.plugins.MerlinSkinThemes.CornerRadius.value})
873                                                 
874                         XMLindent(xmlroot, 0)
875                         
876                         curTree.write(MerlinSkinThemes.selThemeFile)
877                                 
878                         self.readThemes()
879                                 
880         def deleteDesign(self):
881                 if config.plugins.MerlinSkinThemes.Designs["design"].value == "-none-":
882                         self.session.open(MessageBox,_("nothing to delete"), MessageBox.TYPE_ERROR)
883                 else:
884                         curTree = Tree.parse(MerlinSkinThemes.selThemeFile)
885                         xmlroot = curTree.getroot()
886                         designs = xmlroot.find("designs")
887                         for design in designs.findall("design"):
888                                 if design.get("name") == config.plugins.MerlinSkinThemes.Designs["design"].value:
889                                         designs.remove(design)
890                         
891                                         XMLindent(xmlroot, 0)
892
893                                         curTree.write(MerlinSkinThemes.selThemeFile)
894                 
895                                         self.readThemes()
896         
897         # update screen when a different design is selected in section DESIGNS
898         def setDesign(self):
899                 curTree = Tree.parse(MerlinSkinThemes.selThemeFile)
900                 xmlroot = curTree.getroot()
901                 designs = xmlroot.find("designs")
902                 for design in designs.findall("design"):
903                         # design matches the currently selected design in section DESIGN
904                         if design.get("name") == config.plugins.MerlinSkinThemes.Designs["design"].value:
905                                 # for each theme in the design set the value to the selected design
906                                 for element in themeList:
907                                         tmp = design.find(element)
908                                         if tmp is not None:
909                                                 try:
910                                                         if tmp.get("name", None) is not None:
911                                                                 config.plugins.MerlinSkinThemes.Themes[element.lower()].value = tmp.get("name")
912                                                 except:
913                                                         print "[MST] %s not found" %(element)
914
915                                 # for each screen in the design set the value to the selected design
916                                 for screenname in screenList:
917                                         elementList = []
918                                         defaultValue = None
919                                         tmp = design.find(screenname)
920                                         if tmp is not None:
921                                                 try:
922                                                         if tmp.get("name", None) is not None:
923                                                                 config.plugins.MerlinSkinThemes.Screens[screenname].value = tmp.get("name")
924                                                 except:
925                                                         print "[MST] %s not found" %(screenname)
926
927                                 #todo: maybe merge all displays into one config
928                                 # for each LCD screen in the design set the value to the selected design
929                                 for lcdscreen in displayScreenList:
930                                         if design.find(lcdscreen) is not None:
931                                                 tmp = design.find(lcdscreen)
932                                                 if tmp is not None:
933                                                         try:
934                                                                 if tmp.get("name", None) is not None:
935                                                                         config.plugins.MerlinSkinThemes.DisplayScreens[lcdscreen].value = tmp.get("name")
936                                                         except:
937                                                                 print "[MST] %s not found"
938                         
939                                 # for each corner radius in the design set the value to the selected design
940                                 if design.find("CornerRadius") is not None:
941                                         tmp = design.find("CornerRadius")
942                                         if tmp is not None:
943                                                 try:
944                                                         if tmp.get("name", None) is not None:
945                                                                 config.plugins.MerlinSkinThemes.CornerRadius.value = tmp.get("name")
946                                                 except:
947                                                         print "[MST] CornerRadius not found"                                    
948                 
949                                 # refresh Screen
950                                 self["config"].setList(self.clist)
951                                                 
952         def ok(self):
953                 if self.curList == "SkinsList":
954                         if self["SkinsList"].getCurrent()[3][7] == "":
955                                 self.curList = "ConfigList"
956                                 
957                                 if not SkinUser:
958                                         self["ListLabel"].setText(_("Configlist") )
959                                 else:
960                                         self["ListLabel"].setText(_("Configlist") + " - ATTENTION: skin_user.xml found!!!")
961
962                                 if fileExists(MerlinSkinThemes.selSkinFile):
963                                         self.CopyrightInfo()
964                                         
965                                 self.readThemes()
966
967                                 if self["config"].getCurrent()[0] == "Design":
968                                         self["key_green"].setText(_("apply themes"))
969                                         self["key_yellow"].setText(_("delete design"))
970                                 elif self["config"].getCurrent()[0] == "Skin":
971                                         self["key_green"].setText(_("apply themes"))
972                                         self["key_yellow"].setText(_("save as design"))
973                                 else:
974                                         self["key_green"].setText(_("apply themes"))
975                                         self["key_yellow"].setText(_("save as design"))
976                                 
977                                 self["key_green"].show()
978                                 self["key_yellow"].show()
979                                 
980                                 self["SkinsList"].hide()
981                                 self["config"].show()
982                                 
983                                 config.plugins.MerlinSkinThemes.Skin.value = self["SkinsList"].getCurrent()[1][7]
984                                 
985                         else:
986                                 self.CopyrightInfo()
987                                 self.session.open(MessageBox,_("No themes.xml or skin.xml found.\nPlease select a valid skin including themes.xml"), MessageBox.TYPE_ERROR, title=_("Error"))
988                                 
989                 else:
990                         self.curList = "SkinsList"
991                         
992                         if not SkinUser:
993                                 self["ListLabel"].setText(_("Skinlist") )
994                         else:
995                                 self["ListLabel"].setText(_("Skinlist") + " - ATTENTION: skin_user.xml found!!!")
996                         
997                         self["SkinCopyright"].setText("")
998                         
999                         self["key_green"].setText(_("switch to skin"))
1000                         self["key_green"].hide()
1001                         self["key_yellow"].setText("")
1002                         self["key_yellow"].hide()
1003
1004                         #t1 = time.time()
1005                         self.updateSkinList()
1006                         #t2 = time.time()
1007                         #print "[MST] updateSkinList: ", t2 - t1
1008                 
1009                         self["SkinsList"].show()
1010                         self["config"].hide()
1011
1012                         if fileExists(MerlinSkinThemes.selSkinFile):
1013                                 self.CopyrightInfo()
1014                         
1015         def up(self):
1016                 if self.curList == "SkinsList":
1017                         self[self.curList].up()
1018
1019                         if fileExists(MerlinSkinThemes.selSkinFile):
1020                                 self.CopyrightInfo()
1021                         
1022                 else:
1023                         self["config"].instance.moveSelection(self["config"].instance.moveUp)
1024                         if self["config"].getCurrent()[0] == "Design":
1025                                 self["key_green"].setText(_("apply themes"))
1026                                 self["key_yellow"].setText(_("delete design"))
1027                         elif self["config"].getCurrent()[0] == "Skin":
1028                                 self["key_green"].setText(_("apply themes"))
1029                                 self["key_yellow"].setText(_("save as design"))
1030                         else:
1031                                 self["key_green"].setText(_("apply themes"))
1032                                 self["key_yellow"].setText(_("save as design"))
1033         
1034         def down(self):
1035                 if self.curList == "SkinsList":
1036                         self[self.curList].down()
1037
1038                         if fileExists(MerlinSkinThemes.selSkinFile):
1039                                 self.CopyrightInfo()
1040                         
1041                 else:
1042                         self["config"].instance.moveSelection(self["config"].instance.moveDown)
1043                         if self["config"].getCurrent()[0] == "Design":
1044                                 self["key_green"].setText(_("apply themes"))
1045                                 self["key_yellow"].setText(_("delete design"))
1046                         elif self["config"].getCurrent()[0] == "Skin":
1047                                 self["key_green"].setText(_("apply themes"))
1048                                 self["key_yellow"].setText(_("save as design"))
1049                         else:
1050                                 self["key_green"].setText(_("apply themes"))
1051                                 self["key_yellow"].setText(_("save as design"))
1052         
1053         def left(self):
1054                 if self.curList == "SkinsList":
1055                         self[self.curList].pageUp()
1056                 else:
1057                         ConfigListScreen.keyLeft(self)
1058
1059                         if self["config"].getCurrent()[0] in myList:
1060                                 # PreviewPNG anzeigen
1061                                 pngpath = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/preview/" + self["config"].getCurrent()[0] + "/" + self["config"].getCurrent()[1].value + ".png"
1062
1063                                 if not fileExists(pngpath):
1064                                         pngpath = resolveFilename(SCOPE_PLUGINS) + "Extensions/MerlinSkinThemes/noprev.png"
1065
1066                                 self["Preview"].instance.setPixmapFromFile(pngpath)
1067                                 self["Preview"].show()
1068
1069                         if self["config"].getCurrent()[0] == "Design":
1070                                 if config.plugins.MerlinSkinThemes.Designs["design"].value == "-none-":
1071                                         self.readThemes()
1072                                 else:
1073                                         # PreviewPNG anzeigen
1074                                         pngpath = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/preview/" + config.plugins.MerlinSkinThemes.Designs["design"].value + ".png"
1075
1076                                         if not fileExists(pngpath):
1077                                                 pngpath = resolveFilename(SCOPE_PLUGINS) + "Extensions/MerlinSkinThemes/noprev.png"
1078
1079                                         self["Preview"].instance.setPixmapFromFile(pngpath)
1080                                         self["Preview"].show()
1081                                         
1082                                         self.setDesign()
1083                         else:
1084                                 if config.plugins.MerlinSkinThemes.Designs["design"].value != "-none-":
1085                                         config.plugins.MerlinSkinThemes.Designs["design"].value = "-none-"
1086                                         self["config"].invalidate(("Design", config.plugins.MerlinSkinThemes.Designs["design"]))
1087         
1088         def right(self):
1089                 if self.curList == "SkinsList":
1090                         self[self.curList].pageDown()
1091                 else:
1092                         ConfigListScreen.keyRight(self)
1093
1094                         if self["config"].getCurrent()[0] in myList:
1095                                 # PreviewPNG anzeigen
1096                                 pngpath = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/preview/" + self["config"].getCurrent()[0] + "/" + self["config"].getCurrent()[1].value + ".png"
1097
1098                                 if not fileExists(pngpath):
1099                                         pngpath = resolveFilename(SCOPE_PLUGINS) + "Extensions/MerlinSkinThemes/noprev.png"
1100
1101                                 self["Preview"].instance.setPixmapFromFile(pngpath)
1102                                 self["Preview"].show()
1103                                 
1104                         if self["config"].getCurrent()[0] == "Design":
1105                                 if config.plugins.MerlinSkinThemes.Designs["design"].value == "-none-":
1106                                         self.readThemes()
1107                                 else:
1108                                         # PreviewPNG anzeigen
1109                                         pngpath = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/preview/" + config.plugins.MerlinSkinThemes.Designs["design"].value + ".png"
1110
1111                                         if not fileExists(pngpath):
1112                                                 pngpath = resolveFilename(SCOPE_PLUGINS) + "Extensions/MerlinSkinThemes/noprev.png"
1113
1114                                         self["Preview"].instance.setPixmapFromFile(pngpath)
1115                                         self["Preview"].show()
1116
1117                                         self.setDesign()
1118                         else:
1119                                 if config.plugins.MerlinSkinThemes.Designs["design"].value != "-none-":
1120                                         config.plugins.MerlinSkinThemes.Designs["design"].value = "-none-"
1121                                         self["config"].invalidate(("Design", config.plugins.MerlinSkinThemes.Designs["design"]))
1122         
1123         def changedSkinsList(self):
1124                 self["SkinCopyright"].setText("")
1125                 
1126                 MerlinSkinThemes.selSkinName = self["SkinsList"].getCurrent()[1][7]
1127                 
1128                 MerlinSkinThemes.selSkinFile = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/skin.xml"
1129                 MerlinSkinThemes.selThemeFile = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/themes.xml"
1130                 
1131                 #if fileExists(MerlinSkinThemes.selSkinFile):
1132                 #       self.CopyrightInfo()
1133                         
1134                 if config.plugins.MerlinSkinThemes.ShowPrevPNG.value == "1":
1135                         self.loadPreview()
1136                 
1137                 if self["SkinsList"].getCurrent()[2][7] == _("active skin"):
1138                         self["key_green"].hide()
1139                 else:
1140                         self["key_green"].show()
1141
1142                 if self["SkinsList"].getCurrent()[3][7] == _("no skin.xml"):
1143                         self["key_green"].hide()
1144
1145                         self["key_yellow"].show()
1146                         self["key_yellow"].setText(_("delete"))
1147                         
1148                 elif self["SkinsList"].getCurrent()[3][7] == _("no themes.xml"):
1149                         self["key_green"].show()
1150                         
1151                         self["key_yellow"].show()
1152                         self["key_yellow"].setText(_("create themes"))
1153                         
1154                 else:
1155                         self["key_yellow"].show()
1156
1157                         self["key_yellow"].hide()
1158                         #self.readThemes()
1159                         
1160         def updateSkinList(self):
1161                 self["SkinsList"].buildList()
1162
1163         def createThemes(self):
1164                 if fileExists(MerlinSkinThemes.selThemeFile) == False:
1165                         themes = Tree.Element("themes")
1166                         
1167                         curTree = Tree.parse(MerlinSkinThemes.selSkinFile)
1168                         
1169                         for theme in [("colortheme", "colors", "color"), ("fonttheme", "fonts", "font"), ("layouttheme", "layouts", "layout"), ("globalstheme", "globals", ""), ("bordersettheme", "", "borderset"), ("windowstylescrollbartheme", "", ""), ("pngtheme", "", "")]:
1170                                 parentnode1 = Tree.SubElement(themes, theme[0], {"name": "orginal", "value": "active"})
1171                                 if theme[0] == "globalstheme":
1172                                         childnode1 = Tree.SubElement(parentnode1, theme[1], {"name": "sample", "value": "120,50"})
1173                                 elif theme[1] != "":
1174                                         childnode1 = Tree.SubElement(parentnode1, theme[1])
1175                                 parentnode2 = Tree.SubElement(themes, theme[0], {"name": "orginal - work", "value": "inactive"})
1176                                 if theme[0] == "globalstheme":
1177                                         childnode2 = Tree.SubElement(parentnode2, theme[1], {"name": "sample", "value": "120,50"})
1178                                 elif theme[1] != "":                            
1179                                         childnode2 = Tree.SubElement(parentnode2, theme[1])
1180
1181                                 parentnodeSkin = curTree.find(theme[1])                         
1182                                 if theme[0] in ["colortheme", "fonttheme"]:
1183                                         attributeDict = {}
1184                                         for element in parentnodeSkin.findall(theme[2]):
1185                                                 name = element.get("name", None)
1186                                                 if name is not None:
1187                                                         attributeDict["name"] = name
1188                                                 value = element.get("value", None)
1189                                                 if value is not None:
1190                                                         attributeDict["value"] = value
1191                                                 filename = element.get("filename", None)
1192                                                 if filename is not None:
1193                                                         attributeDict["filename"] = filename
1194                                                 scale = element.get("scale", None)
1195                                                 if scale is None and element == "font":
1196                                                         scale = "100"
1197                                                 if scale is not None:
1198                                                         attributeDict["scale"] = scale
1199                                                 replacement = element.get("replacement", None)
1200                                                 if replacement is None and element == "font":
1201                                                         replacement = "0"
1202                                                 if replacement is not None:
1203                                                         attributeDict["replacement"] = replacement
1204                                         
1205                                                 Tree.SubElement(childnode1, theme[2], attributeDict)
1206                                                 Tree.SubElement(childnode2, theme[2], attributeDict)
1207                                 # todo: check if it can be integrated in if
1208                                 elif theme[0] == "bordersettheme":
1209                                         ws = curTree.find("windowstyle")
1210                                         for bs in ws.findall(theme[2]):
1211                                                 if bs.get("name") == "bsWindow":
1212                                                         parentnode1.append(Tree.fromstring(Tree.tostring(bs)))
1213                                                         parentnode2.append(Tree.fromstring(Tree.tostring(bs)))
1214                         
1215                                                 if bs.get("name") == "bsListboxEntry":
1216                                                         parentnode1.append(Tree.fromstring(Tree.tostring(bs)))
1217                                                         parentnode2.append(Tree.fromstring(Tree.tostring(bs)))  
1218                                 elif theme[0] == "windowstylescrollbartheme":
1219                                         for wssb in curTree.findall("windowstylescrollbar"):
1220                                                 if wssb.get("id") == "4":
1221                                                         for sb in wssb.findall("*"):
1222                                                                 parentnode1.append(Tree.fromstring(Tree.tostring(sb)))
1223                                                                 parentnode2.append(Tree.fromstring(Tree.tostring(sb)))
1224                                 elif theme[0] == "layouttheme":
1225                                         Tree.SubElement(childnode1, theme[2], {"name": "sample"}).append(Tree.Comment('Sample: <widget source="Title" render="Label" position="200,77" size="400,40" halign="left" valign="center" font="Regular; 30" foregroundColor="title" backgroundColor="bg2" transparent="1" zPosition="1" />'))
1226                                         Tree.SubElement(childnode2, theme[2], {"name": "sample"})
1227                                 elif theme[0] == "pngtheme":
1228                                         parentnode1.append(Tree.Comment('Sample: name=path+png_name (root=skindir), argb=a:alpha r:red g:green b:blue'))
1229                                         parentnode1.append(Tree.Comment('<png name="design/progress.png" width="814" height="5" argb="#ff55a0ff" />'))
1230                                         parentnode2.append(Tree.Comment('<png name="design/progress.png" width="814" height="5" argb="#ffffa055" />'))
1231                         
1232                         # screenthemes
1233                         screenthemes = Tree.SubElement(themes, "screenthemes")
1234                         for screenname in screenList:
1235                                 screennode = Tree.SubElement(screenthemes, "screens", {"name": screenname })
1236                                 childnode1 = Tree.SubElement(screennode, "screentheme", {"name": "orginal", "value": "active"})
1237                                 childnode2 = Tree.SubElement(screennode, "screentheme", {"name": "orginal - work", "value": "inactive"})
1238                                 
1239                                 skinScreen = curTree.find("screen[@name='%s']" %(screenname))
1240                                 if skinScreen is not None:
1241                                         childnode1.append(Tree.fromstring(Tree.tostring(skinScreen)))
1242                                         childnode2.append(Tree.fromstring(Tree.tostring(skinScreen)))
1243                         
1244                         # displayscreenthemes
1245                         displayscreenthemes = Tree.SubElement(themes, displayTag)
1246                         for displayscreenname in displayScreenList: 
1247                                 displayscreennode = Tree.SubElement(displayscreenthemes, "screens", {"name": displayscreenname, "id": IdString})
1248                                 childnode1 = Tree.SubElement(displayscreennode, displayTag[:-1], {"name": "orginal", "value": "active"})
1249                                 childnode2 = Tree.SubElement(displayscreennode, displayTag[:-1], {"name": "orginal - work", "value": "inactive"})
1250                                 skinScreen = curTree.find("screen[@name='%s'][@id='%s']" %(displayscreenname, IdString))
1251                                 if skinScreen is not None:
1252                                         childnode1.append(Tree.fromstring(Tree.tostring(skinScreen)))
1253                                         childnode2.append(Tree.fromstring(Tree.tostring(skinScreen)))                           
1254
1255                         # Sort
1256                         XMLindent(themes, 0)
1257                         
1258                         # save xml
1259                         themexml = open(MerlinSkinThemes.selThemeFile, "w")
1260                         themexml.write(Tree.tostring(themes))
1261                         themexml.close()
1262                         
1263                         self.updateSkinList()
1264         
1265         def loadPreview(self):
1266                 pngpath = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/prev.png"
1267
1268                 if not fileExists(pngpath):
1269                         pngpath = resolveFilename(SCOPE_PLUGINS) + "Extensions/MerlinSkinThemes/noprev.png"
1270
1271                 self["Preview"].instance.setPixmapFromFile(pngpath)
1272
1273         def MSTMenu(self):
1274                 if fileExists(MerlinSkinThemes.selSkinFile):
1275                         xml = Tree.parse(MerlinSkinThemes.selSkinFile)
1276                         if xml.find("screen[@name='MerlinSkinThemes']"):
1277                                 MSTFixbox = self.session.openWithCallback(self.MSTScrFix,MessageBox,_("Delete screen to fix new MST version?"), MessageBox.TYPE_YESNO)
1278                                 MSTFixbox.setTitle(_("MST screen found"))
1279                         else:
1280                                 self.session.open(MessageBox, _("No MST screen found in this skin.xml!"), MessageBox.TYPE_INFO)
1281                 
1282         def Help(self):
1283                 if self.curList == "SkinsList":
1284                         HelpText = (
1285                                 _("[OK]\nswitch to themes/designs config screen for selected skin\n\n" + 
1286                                 "[create themes] and [delete]\ntakes some time - please wait\n\n" +
1287                                 '[menu]\nremove <screen name="MerlinSkinThemes"...> from selected skin.'
1288                                 "This can fix a greenscreen if skin is not up to date for MST.")
1289                         )
1290
1291                 elif self.curList == "ConfigList":
1292                         HelpText = (
1293                                 _("[OK]\nswitch to skin selection screen\n\n" + 
1294                                 "[apply themes] takes some time - please wait\n\n" + 
1295                                 "[delete design]\ndelete selected design\n\n" + 
1296                                 "[save as design]\nselected themes/screens stored in new design\n\n" +
1297                                 "choose Design: -none-\nto reset themes to active settings/themes")
1298                         )
1299                 
1300                 self.session.open(MessageBox, HelpText, MessageBox.TYPE_INFO, title=_("MerlinSkinThemes - Help"))
1301
1302         def ImageInfo(self):
1303                 InfoText = "Enigma: " + E2ver + " - "
1304
1305                 if Arch64:
1306                         InfoText += "ARM64: " + _("Yes") + " - "
1307
1308                 if ArchArm:
1309                         InfoText += "ARM: " + _("Yes") + " - "
1310
1311                 if ArchMipsel:
1312                         InfoText += "MIPSEL: " + _("Yes") + " - "       
1313                 
1314                 if Merlin:
1315                         InfoText += "Merlin: " + _("Yes") + " - "
1316                 else:
1317                         InfoText += "Merlin: " + _("No") + " - "
1318
1319                 if GP3:
1320                         InfoText += "GP3: " + GP3ver + " - "
1321                 else:
1322                         InfoText += "GP3: " + _("No") + " - "
1323
1324                 if GP4:
1325                         InfoText += "GP4: " + GP4ver
1326                 else:
1327                         InfoText += "GP4: " + _("No")
1328                 
1329                 self["ImageInfo"].setText(InfoText)
1330                 
1331         def CopyrightInfo(self):
1332                 InfoText = ""
1333                 
1334                 curSkin = Tree.parse(MerlinSkinThemes.selSkinFile)
1335                 rootSkin = curSkin.getroot()
1336                 if rootSkin.find("copyright") is not None:
1337                         copyright = rootSkin.find("copyright")
1338                         if copyright.find("orginal") is not None:
1339                                 org = copyright.find("orginal")
1340
1341                                 oAuthor = org.get("author")
1342                                 if oAuthor is None:
1343                                         oAuthor = ""
1344                                 oVersion = org.get("version")
1345                                 if oVersion is None:
1346                                         oVersion = ""
1347                                 oName = org.get("name")
1348                                 if oName is None:
1349                                         oName = ""
1350                                 oSupport = org.get("supporturl")
1351                                 if oSupport is None:
1352                                         oSupport = ""
1353                                 oLicense = org.get("license")
1354                                 if oLicense is None:
1355                                         oLicense = ""
1356                                 
1357                                 OrgText = (
1358                                         "Skin " + oName + " by " + oAuthor + " - Version " + oVersion + " - " + oSupport + "\n\n" +
1359                                         "License:\n" + oLicense
1360                                 )
1361                         
1362                         else:
1363                                 OrgText = (
1364                                         _("Skin ORGINAL - No info available")
1365                                 )
1366                 
1367                         if copyright.find("mod") is not None:
1368                                 mod = copyright.find("mod")
1369
1370                                 mAuthor = mod.get("author")
1371                                 if mAuthor is None:
1372                                         mAuthor = ""
1373                                 mVersion = mod.get("version")
1374                                 if mVersion is None:
1375                                         mVersion = ""
1376                                 mName = mod.get("name")
1377                                 if mName is None:
1378                                         mName = ""
1379                                 mSupport = mod.get("supporturl")
1380                                 if mSupport is None:
1381                                         mSupport = ""
1382                                 
1383                                 ModText = (
1384                                         "Mod:\nSkin " + mName + " by " + mAuthor + " - Version " + mVersion + " - " + mSupport
1385                                 )
1386                         
1387                         else:
1388                                 ModText = (
1389                                         _("Skin MOD - No info available")
1390                                 )
1391                 
1392                         InfoText = OrgText + "\n\n" + ModText
1393
1394                 else:
1395                         InfoText = _("No copyright info available")
1396                         
1397                 #self.session.open(MessageBox, InfoText, MessageBox.TYPE_INFO, title="About Skin - " + MerlinSkinThemes.selSkinName)
1398                 
1399                 self["SkinCopyright"].setText(InfoText)
1400                 
1401         def rgb2hex(self, r, g, b):
1402                 return "#%02X%02X%02X" % (r,g,b)
1403                 
1404         def hex2rgb(self, value):
1405                 value = value.lstrip('#')
1406                 lv = len(value)
1407                 return tuple(int(value[i:i+lv/3], 16) for i in range(0, lv, lv/3))
1408
1409         def argb2hex(self, a, r, g, b):
1410                 return "#%02X%02X%02X%02X" % (a,r,g,b)
1411                 
1412         def Info(self):
1413                 if config.plugins.MerlinSkinThemes.ShowPrevPNG.value == "1":
1414                         config.plugins.MerlinSkinThemes.ShowPrevPNG.value = "0"
1415                         self.session.open(MessageBox, _("Show prev.png - ") + _("Off"), MessageBox.TYPE_INFO, timeout=3)
1416                         self["Preview"].hide()
1417                 else:
1418                         config.plugins.MerlinSkinThemes.ShowPrevPNG.value = "1"
1419                         self.session.open(MessageBox, _("Show prev.png - ") + _("On"), MessageBox.TYPE_INFO, timeout=3)
1420                         self.loadPreview()
1421                         self["Preview"].show()
1422         
1423         def delSkinDir(self):
1424                 print "[MST] Delete: %s" % resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/"
1425                 shutil.rmtree(resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/")
1426                 self.updateSkinList()
1427                 
1428         def restartGUI(self, answer):
1429                 if answer is True:
1430                         #self.setTheme()
1431                         self.session.open(TryQuitMainloop, 3)
1432                 else:
1433                         self.exit(False)
1434
1435         def save(self):
1436                 restartbox = self.session.openWithCallback(self.restartGUI,MessageBox,_("Do you want to Restart the GUI now to apply new skin settings?"), MessageBox.TYPE_YESNO)
1437                 restartbox.setTitle(_("Restart GUI now?"))
1438
1439         def exit(self, cancel=True):
1440                 print '[MST] closing'
1441                 self["SkinsList"].onSelectionChanged.remove(self.changedSkinsList)
1442                 if cancel:
1443                         # exit means settings must not be stored
1444                         config.plugins.MerlinSkinThemes.Skin.cancel()
1445                         config.plugins.MerlinSkinThemes.selSkin.cancel()
1446                         config.plugins.MerlinSkinThemes.ShowPrevPNG.cancel()
1447                         config.plugins.MerlinSkinThemes.CornerRadius.cancel()
1448                         config.plugins.MerlinSkinThemes.applied.cancel()
1449                         if "Designs" in config.plugins.MerlinSkinThemes.dict():
1450                                 for key in config.plugins.MerlinSkinThemes.Designs:
1451                                         config.plugins.MerlinSkinThemes.Designs[key].cancel()
1452                         if "Themes" in config.plugins.MerlinSkinThemes.dict():
1453                                 for key in config.plugins.MerlinSkinThemes.Themes:
1454                                         config.plugins.MerlinSkinThemes.Themes[key].cancel()
1455                         if "Screens" in config.plugins.MerlinSkinThemes.dict():
1456                                 for key in config.plugins.MerlinSkinThemes.Screens:
1457                                         config.plugins.MerlinSkinThemes.Screens[key].cancel()
1458                         if "DisplayScreens" in config.plugins.MerlinSkinThemes.dict():
1459                                 for key in config.plugins.MerlinSkinThemes.DisplayScreens:
1460                                         config.plugins.MerlinSkinThemes.DisplayScreens[key].cancel()
1461                 self.close()
1462                 
1463 def main(session, **kwargs):
1464         session.open(MerlinSkinThemes)
1465
1466 def Plugins(path,**kwargs):
1467         list = [PluginDescriptor(name = "MerlinSkinThemes", description = "MerlinSkinThemes", where = PluginDescriptor.WHERE_PLUGINMENU, icon = "plugin.png", fnc = main)]
1468         return list             
1469
1470 # =================================================================================================
1471
1472 class GetSkinsList(MenuList, MerlinSkinThemes):
1473         SKIN_COMPONENT_KEY = "MerlinSkinThemesList"
1474         SKIN_COMPONENT_DIR_WIDTH = "dirWidth"
1475         SKIN_COMPONENT_STATUS_WIDTH = "statusWidth"
1476         SKIN_COMPONENT_INFO_WIDTH = "infoWidth"
1477
1478         def __init__(self, list, enableWrapAround = True):
1479                 MenuList.__init__(self, list, enableWrapAround, eListboxPythonMultiContent)
1480                 tlf = TemplatedListFonts()
1481                 self.l.setFont(0, gFont(tlf.face(tlf.MEDIUM), tlf.size(tlf.MEDIUM)))
1482                 self.l.setFont(1, gFont(tlf.face(tlf.SMALLER), tlf.size(tlf.SMALLER)))
1483                 self.l.setItemHeight(componentSizes.itemHeight(self.SKIN_COMPONENT_KEY, 30))
1484                 self.selectedIndex = 0
1485                 
1486         def buildList(self):
1487                 list = []
1488                 self.selectedIndex = 0
1489
1490                 sizes = componentSizes[GetSkinsList.SKIN_COMPONENT_KEY]
1491                 configEntryHeight = sizes.get(componentSizes.ITEM_HEIGHT, 30)
1492                 dirWidth = sizes.get(GetSkinsList.SKIN_COMPONENT_DIR_WIDTH, 310)
1493                 statusWidth = sizes.get(GetSkinsList.SKIN_COMPONENT_STATUS_WIDTH, 205)
1494                 infoWidth = sizes.get(GetSkinsList.SKIN_COMPONENT_INFO_WIDTH, 205)
1495                 
1496                 dirs = os.listdir(resolveFilename(SCOPE_SKIN))
1497                 for dir in dirs:
1498                         if os.path.isdir(resolveFilename(SCOPE_SKIN) + dir) is True:
1499                                 curSkinFile = resolveFilename(SCOPE_SKIN) + dir + "/skin.xml"
1500                                 curThemeFile = resolveFilename(SCOPE_SKIN) + dir + "/themes.xml"
1501                                 
1502                                 info = ""
1503                                 status = ""
1504
1505                                 skinxml = False;
1506                                 themexml = False;
1507                                 
1508                                 if fileExists(curSkinFile):
1509                                         skinxml = True;
1510
1511                                 if fileExists(curThemeFile):
1512                                         themexml = True;
1513                                         
1514                                 if skinxml or themexml:
1515                                         if skinxml is False:
1516                                                 info = _("no skin.xml")
1517
1518                                         if themexml is False:
1519                                                 info = _("no themes.xml")
1520
1521                                         if dir == SkinName:
1522                                                 status = _("active skin")
1523
1524                                         res = [
1525                                                 dir,
1526                                                 (eListboxPythonMultiContent.TYPE_TEXT, 5, 0, dirWidth, configEntryHeight, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, dir),
1527                                                 (eListboxPythonMultiContent.TYPE_TEXT, 5 + dirWidth, 0, statusWidth, configEntryHeight, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, status),
1528                                                 (eListboxPythonMultiContent.TYPE_TEXT, 5 + dirWidth + statusWidth, 0, infoWidth, configEntryHeight, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, info),
1529                                         ]
1530                                         list.append(res)
1531
1532                                         
1533                 self.list = list.sort()
1534                 for x in range(len(list)):
1535                         if list[x][2][7] == _("active skin"):
1536                                 self.selectedIndex = x
1537
1538                         
1539                 self.l.setList(list)
1540         
1541 # =================================================================================================
1542                 
1543 class MyConfigSelection(ConfigSelection):
1544         def getText(self):
1545                 if self._descr is not None:
1546                         return self._descr
1547                 descr = self._descr = self.description[self.value]
1548                 return descr
1549                 
1550         def getMulti(self, selected):
1551                 if self._descr is not None:
1552                         descr = self._descr
1553                 else:
1554                         descr = self._descr = self.description[self.value]
1555                 if descr:
1556                         return ("text", descr)
1557                 return ("text", descr)