1 #######################################################################
3 # MerlinSkinThemes for Dreambox/Enigma2/Dreambox OS
4 # Coded by marthom (c)2012 - 2019
6 # Support: board.dreambox.tools
7 # E-Mail: marthom@dreambox-tools.info
9 # This plugin is open source but it is NOT free software.
11 # This plugin may only be distributed to and executed on hardware which
12 # is licensed by Dream Multimedia GmbH.
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.
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.
22 #######################################################################
24 from Plugins.Plugin import PluginDescriptor
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
32 from skin import TemplatedListFonts, componentSizes
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
42 from enigma import eListboxPythonMultiContent, gFont, RT_HALIGN_LEFT, RT_HALIGN_RIGHT, RT_VALIGN_CENTER, getEnigmaVersionString
44 from Tools.HardwareInfo import HardwareInfo
45 from Tools.Directories import resolveFilename, SCOPE_SKIN, SCOPE_PLUGINS, fileExists
47 import xml.etree.cElementTree as Tree
52 # =========================================
53 PluginVersion = "v2.7.0"
54 Title = "MerlinSkinThemes "
56 # =========================================
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"
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"]
74 E2ver = _("not available")
75 if open("/proc/stb/info/model","rb").read() == "dm7080":
76 if fileExists(enigmacontrol):
77 file = open(enigmacontrol, 'r')
79 line = file.readline()
81 if line[:9] == "Version: ":
85 E2ver = getEnigmaVersionString()
89 if fileExists(merlinChk):
95 if fileExists(GP3Chk):
97 file = open(GP3Chk, 'r')
100 line = file.readline()
105 data = data.split("'")
111 if fileExists(GP4Chk):
113 file = open(GP4Chk, 'r')
116 line = file.readline()
121 data = data.split("'")
128 if HardwareInfo().get_device_name() in ('dm900', 'dm920'):
132 DisplayXY = "400x240"
133 elif HardwareInfo().get_device_name() in ('one', 'two'):
135 ArchString = "AARCH64"
136 IdString = "0" #no display
139 if HardwareInfo().get_device_name() == 'dm820':
142 elif HardwareInfo().get_device_name() == 'dm7080':
146 ArchString = "MIPSEL"
147 ModelString = HardwareInfo().get_device_name().upper()
148 displayDict = {"1": "lcdscreenthemes", "2": "oldescreenthemes", "3": "extlcdscreenthemes"}
149 displayTag = displayDict.get(IdString, None)
151 print "------------------------------------------------"
152 print HardwareInfo().get_device_name()
154 print "------------------------------------------------"
158 if fileExists(skin_user_xml):
162 config.plugins.MerlinSkinThemes = ConfigSubsection()
163 config.plugins.MerlinSkinThemes.rebuildSkinOnBoot = ConfigBoolean(default=True)
164 config.plugins.MerlinSkinThemes.Skin = ConfigText(default=SkinName)
165 config.plugins.MerlinSkinThemes.selSkin = ConfigText(default=SkinName)
166 config.plugins.MerlinSkinThemes.ShowPrevPNG = ConfigText(default="1")
167 config.plugins.MerlinSkinThemes.CornerRadius = ConfigText(default="")
168 config.plugins.MerlinSkinThemes.applied = ConfigBoolean(default=False)
170 def initConfigSubDict(sectionName=None):
171 if sectionName == "Design":
172 config.plugins.MerlinSkinThemes.Designs = ConfigSubDict()
173 elif sectionName == "Themes":
174 config.plugins.MerlinSkinThemes.Themes = ConfigSubDict()
175 elif sectionName == "Screens":
176 config.plugins.MerlinSkinThemes.Screens = ConfigSubDict()
177 elif sectionName == "DisplayScreens":
178 config.plugins.MerlinSkinThemes.DisplayScreens = ConfigSubDict()
180 # list of display screens (a.k.a. summaries)
181 displayScreenList = ["InfoBarSummary", "EventView_summary", "StandbySummary", "InfoBarMoviePlayerSummary", "MerlinMusicPlayer2LCDScreen"]
183 screenList = ["InfoBar", "Menu", "PluginBrowser", "ChannelSelection", "MovieSelection", "MoviePlayer", "SecondInfoBar", "GraphMultiEPG", "EventView", "EPGSelection", "MessageBox", "InputBox", "ChoiceBox", "Mute", "Volume", "MerlinMusicPlayer2Screen", "MerlinMusicPlayer2Screen_%s" %(ArchString), "MerlinMusicPlayer2ScreenSaver", "MerlinMusicPlayer2ScreenSaver_%s" %(ArchString)]
185 themeList = ["ColorTheme", "SkinPathTheme", "FontTheme", "BorderSetTheme", "WindowStyleScrollbarTheme", "ComponentTheme", "LayoutTheme", "GlobalsTheme", "PNGTheme" ]
195 def createRectangle(self, width, height, color, filename):
196 image = Image.new(mode='RGBA',size=(width,height),color=color)
199 imageCreator = ImageCreator()
202 value = value.lstrip('#')
204 return tuple(int(value[i:i+lv/4], 16) for i in range(0, lv, lv/4))
206 def XMLindent(elem, level):
207 i = "\n" + (level*" ")
208 #a = "\n%%-%ds" % level
212 if not elem.text or not elem.text.strip():
214 if not elem.tail or not elem.tail.strip():
217 XMLindent(elem, level+1)
218 if not elem.tail or not elem.tail.strip():
221 if level and (not elem.tail or not elem.tail.strip()):
226 def setThemes(themeFile=None, skinFile=None, configDict=None):
227 # set all "inactive", set new theme "active"
228 curTheme = Tree.parse(themeFile)
229 rootTheme = curTheme.getroot()
231 curSkin = Tree.parse(skinFile)
232 rootSkin = curSkin.getroot()
234 if rootSkin.find("merlinskinthemes") is None:
235 mst = Tree.Element("merlinskinthemes", {"text":"Edited with MerlinSkinThemes"})
236 rootSkin.insert(0, mst)
238 for theme in [("colortheme", "colors", "color"), ("fonttheme", "fonts", "font"), ("layouttheme", "layouts", "layout"), ("globalstheme", "globals", ""), ("bordersettheme", "", "borderset"), ("windowstylescrollbartheme", "", ""), ("componenttheme", "components", ""),("pngtheme", "", "")]:
239 #find colortheme in themes.xml
240 if rootTheme.find(theme[0]) is not None:
241 # loop themes in selected theme
242 for currenttheme in rootTheme.findall(theme[0]):
244 # find selected theme
245 if configDict is None:
246 currentValue = config.plugins.MerlinSkinThemes.Themes[theme[0]].value
248 currentValue = configDict.get("config.plugins.MerlinSkinThemes.Themes.%s" %(theme[0]), None)
249 if currenttheme.get("name") == currentValue:
251 currenttheme.set("value", "active")
252 # find all in skin.xml
253 if (theme[1] != "" and theme[2] != ""):
254 skinElement = rootSkin.find(theme[1])
255 # delete all in skin.xml
256 if theme[1] != "layouts" and theme[1] != "components":
257 for element in skinElement.findall(theme[2]):
258 skinElement.remove(element)
260 # find all in themes.xml
261 themeElement = currenttheme.find(theme[1])
262 # add all elements from themes.xml to skin.xml
263 if themeElement is not None:
264 if theme[1] in ["layouts","components","globals"]:
265 skinElement = rootSkin.find(theme[1])
266 rootSkin.remove(skinElement)
267 rootSkin.append(Tree.fromstring(Tree.tostring(themeElement)))
269 for childElement in themeElement.findall(theme[2]):
270 if theme[0] in ["colortheme", "fonttheme"]:
271 name = childElement.get("name", None)
273 attributeDict["name"] = name
274 value = childElement.get("value", None)
275 if value is not None:
276 attributeDict["value"] = value
277 filename = childElement.get("filename", None)
278 if filename is not None:
279 attributeDict["filename"] = filename
280 scale = childElement.get("scale", None)
281 if scale is None and childElement == "font":
283 if scale is not None:
284 attributeDict["scale"] = scale
285 replacement = childElement.get("replacement", None)
286 if replacement is None and childElement == "font":
288 if replacement is not None:
289 attributeDict["replacement"] = replacement
291 Tree.SubElement(skinElement, theme[2], attributeDict)
292 if theme[0] == "bordersettheme":
293 ws = rootSkin.find("windowstyle")
294 if ws.get("id") == "0":
295 for bs in ws.findall(theme[2]):
296 if bs.get("name") == "bsWindow":
297 for px in bs.findall("pixmap"):
300 for tbs in currenttheme.findall(theme[2]):
301 if tbs.get("name") == "bsWindow":
302 for tpx in tbs.findall("pixmap"):
303 bs.append(Tree.fromstring(Tree.tostring(tpx)))
304 if bs.get("name") == "bsListboxEntry":
305 for px in bs.findall("pixmap"):
308 for tbs in currenttheme.findall(theme[2]):
309 if tbs.get("name") == "bsListboxEntry":
310 for tpx in tbs.findall("pixmap"):
311 bs.append(Tree.fromstring(Tree.tostring(tpx)))
312 if theme[0] == "windowstylescrollbartheme":
313 for wssb in rootSkin.findall("windowstylescrollbar"):
314 if wssb.get("id") == "4":
315 for all in wssb.findall("*"):
318 for tall in currenttheme.findall("*"):
319 wssb.append(Tree.fromstring(Tree.tostring(tall)))
320 if theme[0] == "pngtheme":
321 for tp in currenttheme.findall("png"):
322 png_name = tp.get("name")
323 png_width = int(tp.get("width"))
324 png_height = int(tp.get("height"))
325 png_argb = tp.get("argb")
326 acolor = hex2argb(png_argb)
328 if png_name is not None and png_width is not None and png_height is not None and png_argb is not None:
329 imageCreator.createRectangle(png_width, png_height, (acolor[1], acolor[2], acolor[3], acolor[0]), resolveFilename(SCOPE_SKIN) + SkinName + "/" + png_name)
331 # if name does not match set it to inactive
333 currenttheme.set("value", "inactive")
335 if rootTheme.find("screenthemes") is not None:
336 themes = rootTheme.find("screenthemes")
337 for screens in themes.findall("screens"):
338 for screenname in screenList:
339 if screens.get("name") == screenname:
340 for screen in screens.findall("screentheme"):
341 if configDict is None:
342 currentValue = config.plugins.MerlinSkinThemes.Screens[screenname].value
344 currentValue = configDict.get("config.plugins.MerlinSkinThemes.Screens.%s" %(screenname),None)
345 if screen.get("name") == currentValue:
346 screen.set("value", "active")
347 newscreen = screen.find("screen")
350 for SkinScreen in rootSkin.findall("screen"):
351 if SkinScreen.get("name") == screenname:
352 rootSkin.remove(SkinScreen)
355 rootSkin.append(Tree.fromstring(Tree.tostring(newscreen)))
358 screen.set("value", "inactive")
360 # LCD / OLED / External LCD
361 if displayTag is not None:
362 if rootTheme.find(displayTag) is not None:
363 themes = rootTheme.find(displayTag)
364 for screens in themes.findall("screens"):
365 for displayscreenname in displayScreenList:
366 if screens.get("name") == displayscreenname:
367 for screen in screens.findall(displayTag[:-1]):
368 if configDict is None:
369 currentValue = config.plugins.MerlinSkinThemes.DisplayScreens[displayscreenname].value
371 currentValue = configDict.get("config.plugins.MerlinSkinThemes.DisplayScreens.%s" %(displayscreenname), None)
372 if screen.get("name") == currentValue:
373 screen.set("value", "active")
374 newscreen = screen.find("screen")
377 for SkinScreen in rootSkin.findall("screen"):
378 if SkinScreen.get("name") == displayscreenname and SkinScreen.get("id") == IdString:
379 rootSkin.remove(SkinScreen)
382 rootSkin.append(Tree.fromstring(Tree.tostring(newscreen)))
385 screen.set("value", "inactive")
387 # corner Radius in skin.xml in allen eLabel ersetzen
388 if config.plugins.MerlinSkinThemes.CornerRadius.value <> "":
389 for elabel in rootSkin.findall('.//eLabel[@cornerRadius]'):
390 if 'cornerRadius' in elabel.attrib:
391 if rootTheme.find("cornerradius") is not None:
392 crtheme = rootTheme.find("cornerradius")
394 if elabel.get("cornerRadius") <> crtheme.get("exclude"):
395 elabel.set("cornerRadius", config.plugins.MerlinSkinThemes.CornerRadius.value)
397 for r in crtheme.findall("radius"):
398 if r.get("name") == config.plugins.MerlinSkinThemes.CornerRadius.value:
399 r.set("value", "active")
401 r.set("value", "inactive")
403 XMLindent(rootSkin, 0)
404 curSkin.write(skinFile)
407 xmlTree = Tree.parse(skinFile)
408 xmlRoot = xmlTree.getroot()
409 xmlString = Tree.tostring(xmlRoot)
411 if rootTheme.find("skinpaththemes") is not None:
412 spt = rootTheme.find("skinpaththemes")
413 for theme in spt.findall("theme"):
414 if configDict is None:
415 currentValue = config.plugins.MerlinSkinThemes.Themes["skinpaththeme"].value
417 currentValue = configDict.get("config.plugins.MerlinSkinThemes.Themes.%s" %(skinpaththeme), None)
418 if theme.get("name") == currentValue:
419 newPath = theme.get("path")
420 theme.set("value", "active")
422 theme.set("value", "inactive")
424 for theme in spt.findall("theme"):
425 xmlString = xmlString.replace(theme.get("path"), newPath)
427 xmlSkin = open(skinFile, "w")
428 xmlSkin.write(xmlString)
431 curTheme.write(themeFile)
433 class MerlinSkinThemes(Screen, HelpableScreen, ConfigListScreen):
435 <screen position="center,center" size="1920,1080" title="%s" backgroundColor="#00808080" >
436 <widget name="DescLabel" position="10,10" size="1900,40" font="Regular;26" zPosition="2" valign="center" halign="center" />
438 <widget name="ListLabel" position="10,60" size="945,40" font="Regular;26" zPosition="2" valign="center" halign="left" />
439 <widget name="ImageInfo" position="965,60" size="945,40" font="Regular;26" zPosition="2" halign="left" />
441 <widget name="SkinsList" position="10,110" size="945,910" scrollbarMode="showOnDemand" zPosition="1" />
442 <widget name="config" position="10,110" size="945,910" scrollbarMode="showOnDemand" zPosition="1" />
444 <widget name="SkinCopyright" position="965,110" size="945,200" font="Regular;18" zPosition="2" halign="left" />
445 <widget name="Preview" position="965,320" size="945,700" alphatest="blend" />
447 <widget name="key_red" position="10,1030" size="200,40" valign="center" halign="center" zPosition="3" transparent="1" font="Regular;24" />
448 <widget name="key_green" position="258,1030" size="200,40" valign="center" halign="center" zPosition="3" transparent="1" font="Regular;24" />
449 <widget name="key_yellow" position="506,1030" size="200,40" valign="center" halign="center" zPosition="3" transparent="1" font="Regular;24" />
450 <widget name="key_blue" position="755,1030" size="200,40" valign="center" halign="center" zPosition="3" transparent="1" font="Regular;24" />
452 <ePixmap name="red" position="10,1030" zPosition="1" size="200,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="blend" />
453 <ePixmap name="green" position="258,1030" zPosition="1" size="200,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="blend" />
454 <ePixmap name="yellow" position="506,1030" zPosition="1" size="200,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="blend" />
455 <ePixmap name="blue" position="755,1030" zPosition="1" size="200,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="blend" />
456 </screen>"""% ("MerlinSkinThemes")
462 def __init__(self, session):
463 print "[MST] " + PluginVersion + " running..."
465 self.session = session
467 Screen.__init__(self, session)
468 HelpableScreen.__init__(self)
471 ConfigListScreen.__init__(self, self.clist)
473 self.setTitle(Title + " " + PluginVersion + " - " + Author)
476 self["ListLabel"] = Label(_("Skinlist") )
478 self["ListLabel"] = Label(_("Skinlist") + " - ATTENTION: skin_user.xml found!!!")
480 self["DescLabel"] = Label(Title + " " + PluginVersion + " " + Author)
481 self["SkinCopyright"] = Label()
482 self["Preview"] = Pixmap()
483 self["ImageInfo"] = Label()
485 self.curList = "SkinsList"
487 self["key_red"] = Button(_("exit"))
488 self["key_green"] = Button(_("switch to skin"))
489 self["key_yellow"] = Button(_("save as design"))
490 self["key_blue"] = Button(_("open config"))
493 self["SkinsList"] = GetSkinsList([])
495 self.onSelectionChanged = [ ]
497 self["ColorActions"] = HelpableActionMap(self, "ColorActions",
499 "red": self.buttonRed,
500 "green": self.buttonGreen,
501 "yellow": self.buttonYellow,
502 "blue": self.openConfig,
505 self["DirectionActions"] = HelpableActionMap(self, "DirectionActions",
507 "up": (self.up, _("Move cursor up")),
508 "down": (self.down, _("Move cursor down")),
509 "left": (self.left, _("Move cursor left")),
510 "right": (self.right, _("Move cursor right")),
513 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
516 "cancel": (self.exit, _("Close plugin")),
519 self["TeleTextActions"] = HelpableActionMap(self, "TeleTextActions",
521 "help": (self.Help, ""),
522 "info": (self.Info, ""),
525 self["MenuActions"] = HelpableActionMap(self, "MenuActions",
527 "menu": (self.MSTMenu, ""),
530 self.updateSkinList()
532 MerlinSkinThemes.selSkinName = self["SkinsList"].getCurrent()[1][7]
533 MerlinSkinThemes.selSkinFile = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/skin.xml"
534 MerlinSkinThemes.selThemeFile = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/themes.xml"
536 self.onLayoutFinish.append(self.startRun)
538 def openConfig(self):
539 self.session.open(MerlinSkinThemesConfig)
542 self["SkinsList"].onSelectionChanged.append(self.changedSkinsList)
544 MerlinSkinThemes.selSkinName = self["SkinsList"].getCurrent()[1][7]
545 MerlinSkinThemes.selSkinFile = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/skin.xml"
546 MerlinSkinThemes.selThemeFile = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/themes.xml"
548 self["config"].hide()
550 self["SkinsList"].moveToIndex(self["SkinsList"].selectedIndex)
553 if fileExists(MerlinSkinThemes.selSkinFile):
557 def readThemes(self):
561 xml = Tree.parse(MerlinSkinThemes.selThemeFile)
564 selSkinList.append(MerlinSkinThemes.selSkinName)
565 config.plugins.MerlinSkinThemes.selSkin = MyConfigSelection(default=MerlinSkinThemes.selSkinName, choices = selSkinList)
566 self.clist.append(getConfigListEntry(" ", ))
567 self.clist.append(getConfigListEntry("Skin", config.plugins.MerlinSkinThemes.selSkin))
569 #####################
571 #####################
577 # this reads all <design> and its themes that are defined in <designs>
578 # name of <design> is read and displayed in the section DESIGNS, active one is set as default
579 self.clist.append(getConfigListEntry(" ", ))
580 self.clist.append(getConfigListEntry(" " + u'\u00b7' + " DESIGNS", ))
582 if xml.find("designs") is not None:
583 initDesignsDone = False
584 ds = xml.find("designs")
585 for element in ["design"]:
587 elementList.append("-none-")
588 defaultValue = "-none-"
589 for design in ds.findall(element):
590 elementList.append(design.get("name"))
591 #if design.get("value") == "active":
592 #defaultValue = design.get("name")
594 if len(elementList) > 0:
595 if not initDesignsDone:
596 initConfigSubDict("Design")
597 initDesignsDone = True
598 config.plugins.MerlinSkinThemes.Designs[element] = MyConfigSelection(default=defaultValue, choices = elementList)
599 self.clist.append(getConfigListEntry("Design", config.plugins.MerlinSkinThemes.Designs[element]))
604 # name of theme is read and displayed in the section THEMES, active one is set as default
605 self.clist.append(getConfigListEntry(" ", ))
606 self.clist.append(getConfigListEntry(" " + u'\u00b7' + " THEMES", ))
608 themesInitDone = False
609 for element in themeList:
612 if xml.find(element.lower()) is not None:
613 for theme in xml.findall(element.lower()):
614 elementList.append(theme.get("name"))
615 if theme.get("value") == "active":
616 defaultValue = theme.get("name")
618 if len(elementList) > 0:
619 if not themesInitDone:
620 initConfigSubDict("Themes")
621 themesInitDone = True
622 config.plugins.MerlinSkinThemes.Themes[element.lower()] = MyConfigSelection(default=defaultValue, choices = elementList)
623 self.clist.append(getConfigListEntry(element, config.plugins.MerlinSkinThemes.Themes[element.lower()]))
629 # <!-- multiple screens possible -->
630 # <screens name="screenname">
631 # <!-- multiple screentheme possible -->
633 # <screen>...</screen>
637 self.clist.append(getConfigListEntry(" ", ))
638 self.clist.append(getConfigListEntry(" " + u'\u00b7' + " SCREENS", ))
640 if xml.find("screenthemes") is not None:
641 st = xml.find("screenthemes")
642 initScreenDone = False
643 for screens in st.findall("screens"):
644 for screenname in screenList:
647 if screens.get("name") == screenname:
648 for themes in screens.findall("screentheme"):
649 elementList.append(themes.get("name"))
650 if themes.get("value") == "active":
651 defaultValue = themes.get("name")
652 if len(elementList)>0:
653 if not initScreenDone:
654 initConfigSubDict("Screens")
655 initScreenDone = True
656 config.plugins.MerlinSkinThemes.Screens[screenname] = MyConfigSelection(default=defaultValue, choices = elementList)
657 self.clist.append(getConfigListEntry(screenname, config.plugins.MerlinSkinThemes.Screens[screenname]))
659 #########################
660 # -- Display Screens -- #
661 #########################
662 # <lcdscreenthemes> / <oledscreenthemes> / <extlcdscreenthemes>
663 # <!-- multiple screens possible -->
664 # <screens name="screenname">
665 # <!-- multiple lcdscreentheme possible -->
666 # <lcdscreentheme> / <oledscreentheme> / <extlcdscreentheme>
667 # <screen>...</screen>
668 # </lcdscreentheme> / </oledscreentheme> / </extlcdscreentheme>
670 # </lcdscreenthemes> / <oledscreenthemes> / </extlcdscreenthemes>
672 if displayTag is not None:
673 if xml.find(displayTag) is not None:
674 self.clist.append(getConfigListEntry(" ", ))
675 self.clist.append(getConfigListEntry(" " + u'\u00b7' + " DISPLAY SCREENS ID=%s (%s) %s" %(IdString, ModelString, DisplayXY ), ))
677 initDisplayScreenDone = False
678 for element in displayScreenList:
681 st = xml.find(displayTag)
682 if st.find("screens[@name='%s']" %(element)) is not None:
683 lst = st.find("screens[@name='%s']" %(element))
684 for th in lst.findall(displayTag[:-1]):
685 for screen in th.findall("screen"):
686 if screen.get("name") == element and screen.get("id") == IdString:
687 elementList.append(th.get("name"))
688 if th.get("value") == "active":
689 defaultValue = th.get("name")
691 if len(elementList) > 0:
692 if not initDisplayScreenDone:
693 initConfigSubDict("DisplayScreens")
694 initDisplayScreenDone = True
695 config.plugins.MerlinSkinThemes.DisplayScreens[element] = MyConfigSelection(default=defaultValue, choices = elementList)
696 self.clist.append(getConfigListEntry(element, config.plugins.MerlinSkinThemes.DisplayScreens[element]))
698 ######################
699 # -- cornerRadius -- #
700 ######################
704 if xml.find("cornerradius") is not None:
705 self.clist.append(getConfigListEntry(" ", ))
706 self.clist.append(getConfigListEntry(" " + u'\u00b7' + " CORNERRADIUS", ))
710 cr = xml.find("cornerradius")
711 for cradius in cr.findall("radius"):
712 elementList.append(cradius.get("name"))
713 if cradius.get("value") == "active":
714 defaultValue = cradius.get("name")
716 if len(elementList) > 0:
717 config.plugins.MerlinSkinThemes.CornerRadius = MyConfigSelection(default=defaultValue, choices = elementList)
718 self.clist.append(getConfigListEntry("CornerRadius", config.plugins.MerlinSkinThemes.CornerRadius))
720 except Exception as error:
722 print "[MST] themes.xml in " + MerlinSkinThemes.selSkinName + " corrupt!"
723 self.clist.append(getConfigListEntry(" ", ))
724 self.clist.append(getConfigListEntry(_(">>> ERROR - themes.xml in " + MerlinSkinThemes.selSkinName + " corrupt! <<<"), ))
726 self["config"].setList(self.clist)
728 def buttonGreen(self):
729 if self.curList == "SkinsList":
731 sel = self["SkinsList"].getCurrent()
732 if sel[1][7] == "Default Skin":
733 skinfile = "skin.xml"
735 skinfile = "%s/skin.xml" % sel[1][7]
737 # Dr. Best Infobar position
738 if fileExists("/usr/share/enigma2/merlin_setup.xml"):
739 config.merlin2.infobar_position_offset_x.value = 0
740 config.merlin2.infobar_position_offset_x.save()
741 config.merlin2.infobar_position_offset_y.value = 0
742 config.merlin2.infobar_position_offset_y.save()
743 config.merlin2.movieplayer_infobar_position_offset_x.value = 0
744 config.merlin2.movieplayer_infobar_position_offset_x.save()
745 config.merlin2.movieplayer_infobar_position_offset_y.value = 0
746 config.merlin2.movieplayer_infobar_position_offset_y.save()
748 config.skin.primary_skin.value = skinfile
749 config.skin.primary_skin.save()
750 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)
751 restartbox.setTitle(_("Restart GUI now?"))
752 elif self.curList == "ConfigList":
753 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)
754 askBox.setTitle(_("Apply themes now?"))
756 def askYN(self, answer):
758 setThemes(MerlinSkinThemes.selThemeFile, MerlinSkinThemes.selSkinFile, None)
759 config.plugins.MerlinSkinThemes.applied.value = True
760 config.plugins.MerlinSkinThemes.applied.save()
761 for x in self["config"].list:
765 if SkinName == MerlinSkinThemes.selSkinName:
766 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)
767 restartbox.setTitle(_("Restart GUI now?"))
770 self.session.open(MessageBox, _("Changes to skin " + MerlinSkinThemes.selSkinName + " ready!"), MessageBox.TYPE_INFO)
772 def MSTScrFix(self, answer):
774 curSkin = Tree.parse(MerlinSkinThemes.selSkinFile)
775 rootSkin = curSkin.getroot()
776 mstscreen = rootSkin.find("screen[@name='MerlinSkinThemes']")
777 rootSkin.remove(mstscreen)
779 XMLindent(rootSkin, 0)
780 curSkin.write(MerlinSkinThemes.selSkinFile)
782 self.updateSkinList()
784 self.session.open(MessageBox, '<screen name="MerlinSkinThemes"...> was removed from selected skin.', MessageBox.TYPE_INFO)
789 def buttonYellow(self):
790 if self.curList == "SkinsList":
791 if self["SkinsList"].getCurrent()[3][7] == _("no themes.xml"):
794 if self["SkinsList"].getCurrent()[3][7] == _("no skin.xml"):
797 elif self.curList == "ConfigList":
798 if self["config"].getCurrent()[0] == "Design":
804 self.session.openWithCallback(self.saveDesign, InputBox, title=_("Please enter designname!"))
806 # write a new design into <designs>
807 def saveDesign(self, designname):
808 if designname is not None:
810 designname = designname.strip()
812 curTree = Tree.parse(MerlinSkinThemes.selThemeFile)
813 xmlroot = curTree.getroot()
815 if xmlroot.find("designs") is None:
816 xmldesigns = Tree.SubElement(xmlroot, "designs")
818 xmldesigns = xmlroot.find("designs")
820 # check if design exists
821 if xmldesigns.find("design[@name='" + designname + "']") is not None:
822 xmldesigns.remove(xmldesigns.find("design[@name='" + designname + "']"))
825 xmldesign = Tree.SubElement(xmldesigns, "design", {"name": designname, "value": "active"})
827 for element in themeList:
828 # remark: for now don't handle it here. Needs alignment
829 if element == "SkinPathTheme":
831 # check if theme exists
832 if element.lower() in config.plugins.MerlinSkinThemes.Themes.keys():
833 if xmlroot.find("%s[@name='" %(element.lower()) + config.plugins.MerlinSkinThemes.Themes[element.lower()].value + "']" ) is not None:
834 if xmldesign.find(element) is not None:
835 td = xmldesign.find(element)
836 td.set("name", config.plugins.MerlinSkinThemes.Themes[element.lower()].value)
838 Tree.SubElement(xmldesign, element, {"name": config.plugins.MerlinSkinThemes.Themes[element.lower()].value })
841 # todo: same check required like for themes? is it really possible to define it in Designs?
842 if xmlroot.find("skinpaththemes") is not None:
843 t = xmlroot.find("skinpaththemes")
845 if t.find("theme[@name='" + config.plugins.MerlinSkinThemes.Themes["skinpaththemes"].value + "']") is not None:
846 if xmldesign.find("SkinPathTheme") is not None:
847 td = xmldesign.find("SkinPathTheme")
848 td.set("name", config.plugins.MerlinSkinThemes.Themes["skinpaththemes"].value)
850 Tree.SubElement(xmldesign, "SkinPathTheme", {"name": config.plugins.MerlinSkinThemes.Themes["skinpaththemes"].value})
853 if xmlroot.find("screenthemes") is not None:
854 t = xmlroot.find("screenthemes")
856 for element in screenList:
857 if t.find("screens[@name='%s']" %(element)) is not None:
858 ts = t.find("screens[@name='%s']" %(element))
859 if ts.find("screentheme[@name='" + config.plugins.MerlinSkinThemes.Screens[element].value + "']") is not None:
860 Tree.SubElement(xmldesign, element, {"name": config.plugins.MerlinSkinThemes.Screens[element].value})
863 if displayTag is not None:
864 if xmlroot.find(displayTag) is not None:
865 t = xmlroot.find(displayTag)
867 for element in displayScreenList:
868 if t.find("screens[@name='%s']" %(element)) is not None:
869 ts = t.find("screens[@name='%s']" %(element))
870 if ts.find("%s[@name='" %(displayTag[:-1]) + config.plugins.MerlinSkinThemes.DisplayScreens[element].value + "']") is not None:
871 # todo: LCDInfoBar vs. InfoBarSummary!!!! wie geht das?
872 Tree.SubElement(xmldesign, element, {"name": config.plugins.MerlinSkinThemes.DisplayScreens[element].value})
875 if xmlroot.find("cornerradius") is not None:
876 if xmldesign.find("CornerRadius") is not None:
877 td = xmldesign.find("CornerRadius")
878 td.set("name", config.plugins.MerlinSkinThemes.CornerRadius.value)
880 Tree.SubElement(xmldesign, "CornerRadius", {"name": config.plugins.MerlinSkinThemes.CornerRadius.value})
882 XMLindent(xmlroot, 0)
884 curTree.write(MerlinSkinThemes.selThemeFile)
888 def deleteDesign(self):
889 if config.plugins.MerlinSkinThemes.Designs["design"].value == "-none-":
890 self.session.open(MessageBox,_("nothing to delete"), MessageBox.TYPE_ERROR)
892 curTree = Tree.parse(MerlinSkinThemes.selThemeFile)
893 xmlroot = curTree.getroot()
894 designs = xmlroot.find("designs")
895 for design in designs.findall("design"):
896 if design.get("name") == config.plugins.MerlinSkinThemes.Designs["design"].value:
897 designs.remove(design)
899 XMLindent(xmlroot, 0)
901 curTree.write(MerlinSkinThemes.selThemeFile)
905 # update screen when a different design is selected in section DESIGNS
907 curTree = Tree.parse(MerlinSkinThemes.selThemeFile)
908 xmlroot = curTree.getroot()
909 designs = xmlroot.find("designs")
910 for design in designs.findall("design"):
911 # design matches the currently selected design in section DESIGN
912 if design.get("name") == config.plugins.MerlinSkinThemes.Designs["design"].value:
913 # for each theme in the design set the value to the selected design
914 for element in themeList:
915 tmp = design.find(element)
918 if tmp.get("name", None) is not None:
919 config.plugins.MerlinSkinThemes.Themes[element.lower()].value = tmp.get("name")
921 print "[MST] %s not found" %(element)
923 # for each screen in the design set the value to the selected design
924 for screenname in screenList:
927 tmp = design.find(screenname)
930 if tmp.get("name", None) is not None:
931 config.plugins.MerlinSkinThemes.Screens[screenname].value = tmp.get("name")
933 print "[MST] %s not found" %(screenname)
935 #todo: maybe merge all displays into one config
936 # for each LCD screen in the design set the value to the selected design
937 for lcdscreen in displayScreenList:
938 if design.find(lcdscreen) is not None:
939 tmp = design.find(lcdscreen)
942 if tmp.get("name", None) is not None:
943 config.plugins.MerlinSkinThemes.DisplayScreens[lcdscreen].value = tmp.get("name")
945 print "[MST] %s not found"
947 # for each corner radius in the design set the value to the selected design
948 if design.find("CornerRadius") is not None:
949 tmp = design.find("CornerRadius")
952 if tmp.get("name", None) is not None:
953 config.plugins.MerlinSkinThemes.CornerRadius.value = tmp.get("name")
955 print "[MST] CornerRadius not found"
958 self["config"].setList(self.clist)
961 if self.curList == "SkinsList":
962 if self["SkinsList"].getCurrent()[3][7] == "":
963 self.curList = "ConfigList"
966 self["ListLabel"].setText(_("Configlist") )
968 self["ListLabel"].setText(_("Configlist") + " - ATTENTION: skin_user.xml found!!!")
970 if fileExists(MerlinSkinThemes.selSkinFile):
975 if self["config"].getCurrent()[0] == "Design":
976 self["key_green"].setText(_("apply themes"))
977 self["key_yellow"].setText(_("delete design"))
978 elif self["config"].getCurrent()[0] == "Skin":
979 self["key_green"].setText(_("apply themes"))
980 self["key_yellow"].setText(_("save as design"))
982 self["key_green"].setText(_("apply themes"))
983 self["key_yellow"].setText(_("save as design"))
985 self["key_green"].show()
986 self["key_yellow"].show()
988 self["SkinsList"].hide()
989 self["config"].show()
991 config.plugins.MerlinSkinThemes.Skin.value = self["SkinsList"].getCurrent()[1][7]
995 self.session.open(MessageBox,_("No themes.xml or skin.xml found.\nPlease select a valid skin including themes.xml"), MessageBox.TYPE_ERROR, title=_("Error"))
998 self.curList = "SkinsList"
1001 self["ListLabel"].setText(_("Skinlist") )
1003 self["ListLabel"].setText(_("Skinlist") + " - ATTENTION: skin_user.xml found!!!")
1005 self["SkinCopyright"].setText("")
1007 self["key_green"].setText(_("switch to skin"))
1008 self["key_green"].hide()
1009 self["key_yellow"].setText("")
1010 self["key_yellow"].hide()
1013 self.updateSkinList()
1015 #print "[MST] updateSkinList: ", t2 - t1
1017 self["SkinsList"].show()
1018 self["config"].hide()
1020 if fileExists(MerlinSkinThemes.selSkinFile):
1021 self.CopyrightInfo()
1024 if self.curList == "SkinsList":
1025 self[self.curList].up()
1027 if fileExists(MerlinSkinThemes.selSkinFile):
1028 self.CopyrightInfo()
1031 self["config"].instance.moveSelection(self["config"].instance.moveUp)
1032 if self["config"].getCurrent()[0] == "Design":
1033 self["key_green"].setText(_("apply themes"))
1034 self["key_yellow"].setText(_("delete design"))
1035 elif self["config"].getCurrent()[0] == "Skin":
1036 self["key_green"].setText(_("apply themes"))
1037 self["key_yellow"].setText(_("save as design"))
1039 self["key_green"].setText(_("apply themes"))
1040 self["key_yellow"].setText(_("save as design"))
1043 if self.curList == "SkinsList":
1044 self[self.curList].down()
1046 if fileExists(MerlinSkinThemes.selSkinFile):
1047 self.CopyrightInfo()
1050 self["config"].instance.moveSelection(self["config"].instance.moveDown)
1051 if self["config"].getCurrent()[0] == "Design":
1052 self["key_green"].setText(_("apply themes"))
1053 self["key_yellow"].setText(_("delete design"))
1054 elif self["config"].getCurrent()[0] == "Skin":
1055 self["key_green"].setText(_("apply themes"))
1056 self["key_yellow"].setText(_("save as design"))
1058 self["key_green"].setText(_("apply themes"))
1059 self["key_yellow"].setText(_("save as design"))
1062 if self.curList == "SkinsList":
1063 self[self.curList].pageUp()
1065 ConfigListScreen.keyLeft(self)
1067 if self["config"].getCurrent()[0] in myList:
1068 # PreviewPNG anzeigen
1069 pngpath = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/preview/" + self["config"].getCurrent()[0] + "/" + self["config"].getCurrent()[1].value + ".png"
1071 if not fileExists(pngpath):
1072 pngpath = resolveFilename(SCOPE_PLUGINS) + "Extensions/MerlinSkinThemes/noprev.png"
1074 self["Preview"].instance.setPixmapFromFile(pngpath)
1075 self["Preview"].show()
1077 if self["config"].getCurrent()[0] == "Design":
1078 if config.plugins.MerlinSkinThemes.Designs["design"].value == "-none-":
1081 # PreviewPNG anzeigen
1082 pngpath = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/preview/" + config.plugins.MerlinSkinThemes.Designs["design"].value + ".png"
1084 if not fileExists(pngpath):
1085 pngpath = resolveFilename(SCOPE_PLUGINS) + "Extensions/MerlinSkinThemes/noprev.png"
1087 self["Preview"].instance.setPixmapFromFile(pngpath)
1088 self["Preview"].show()
1092 if config.plugins.MerlinSkinThemes.Designs["design"].value != "-none-":
1093 config.plugins.MerlinSkinThemes.Designs["design"].value = "-none-"
1094 self["config"].invalidate(("Design", config.plugins.MerlinSkinThemes.Designs["design"]))
1097 if self.curList == "SkinsList":
1098 self[self.curList].pageDown()
1100 ConfigListScreen.keyRight(self)
1102 if self["config"].getCurrent()[0] in myList:
1103 # PreviewPNG anzeigen
1104 pngpath = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/preview/" + self["config"].getCurrent()[0] + "/" + self["config"].getCurrent()[1].value + ".png"
1106 if not fileExists(pngpath):
1107 pngpath = resolveFilename(SCOPE_PLUGINS) + "Extensions/MerlinSkinThemes/noprev.png"
1109 self["Preview"].instance.setPixmapFromFile(pngpath)
1110 self["Preview"].show()
1112 if self["config"].getCurrent()[0] == "Design":
1113 if config.plugins.MerlinSkinThemes.Designs["design"].value == "-none-":
1116 # PreviewPNG anzeigen
1117 pngpath = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/preview/" + config.plugins.MerlinSkinThemes.Designs["design"].value + ".png"
1119 if not fileExists(pngpath):
1120 pngpath = resolveFilename(SCOPE_PLUGINS) + "Extensions/MerlinSkinThemes/noprev.png"
1122 self["Preview"].instance.setPixmapFromFile(pngpath)
1123 self["Preview"].show()
1127 if config.plugins.MerlinSkinThemes.Designs["design"].value != "-none-":
1128 config.plugins.MerlinSkinThemes.Designs["design"].value = "-none-"
1129 self["config"].invalidate(("Design", config.plugins.MerlinSkinThemes.Designs["design"]))
1131 def changedSkinsList(self):
1132 self["SkinCopyright"].setText("")
1134 MerlinSkinThemes.selSkinName = self["SkinsList"].getCurrent()[1][7]
1136 MerlinSkinThemes.selSkinFile = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/skin.xml"
1137 MerlinSkinThemes.selThemeFile = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/themes.xml"
1139 #if fileExists(MerlinSkinThemes.selSkinFile):
1140 # self.CopyrightInfo()
1142 if config.plugins.MerlinSkinThemes.ShowPrevPNG.value == "1":
1145 if self["SkinsList"].getCurrent()[2][7] == _("active skin"):
1146 self["key_green"].hide()
1148 self["key_green"].show()
1150 if self["SkinsList"].getCurrent()[3][7] == _("no skin.xml"):
1151 self["key_green"].hide()
1153 self["key_yellow"].show()
1154 self["key_yellow"].setText(_("delete"))
1156 elif self["SkinsList"].getCurrent()[3][7] == _("no themes.xml"):
1157 self["key_green"].show()
1159 self["key_yellow"].show()
1160 self["key_yellow"].setText(_("create themes"))
1163 self["key_yellow"].show()
1165 self["key_yellow"].hide()
1168 def updateSkinList(self):
1169 self["SkinsList"].buildList()
1171 def createThemes(self):
1172 if fileExists(MerlinSkinThemes.selThemeFile) == False:
1173 themes = Tree.Element("themes")
1175 curTree = Tree.parse(MerlinSkinThemes.selSkinFile)
1177 for theme in [("colortheme", "colors", "color"), ("fonttheme", "fonts", "font"), ("layouttheme", "layouts", "layout"), ("globalstheme", "globals", ""), ("bordersettheme", "", "borderset"), ("windowstylescrollbartheme", "", ""), ("pngtheme", "", "")]:
1178 parentnode1 = Tree.SubElement(themes, theme[0], {"name": "orginal", "value": "active"})
1179 if theme[0] == "globalstheme":
1180 childnode1 = Tree.SubElement(parentnode1, theme[1], {"name": "sample", "value": "120,50"})
1181 elif theme[1] != "":
1182 childnode1 = Tree.SubElement(parentnode1, theme[1])
1183 parentnode2 = Tree.SubElement(themes, theme[0], {"name": "orginal - work", "value": "inactive"})
1184 if theme[0] == "globalstheme":
1185 childnode2 = Tree.SubElement(parentnode2, theme[1], {"name": "sample", "value": "120,50"})
1186 elif theme[1] != "":
1187 childnode2 = Tree.SubElement(parentnode2, theme[1])
1189 parentnodeSkin = curTree.find(theme[1])
1190 if theme[0] in ["colortheme", "fonttheme"]:
1192 for element in parentnodeSkin.findall(theme[2]):
1193 name = element.get("name", None)
1194 if name is not None:
1195 attributeDict["name"] = name
1196 value = element.get("value", None)
1197 if value is not None:
1198 attributeDict["value"] = value
1199 filename = element.get("filename", None)
1200 if filename is not None:
1201 attributeDict["filename"] = filename
1202 scale = element.get("scale", None)
1203 if scale is None and element == "font":
1205 if scale is not None:
1206 attributeDict["scale"] = scale
1207 replacement = element.get("replacement", None)
1208 if replacement is None and element == "font":
1210 if replacement is not None:
1211 attributeDict["replacement"] = replacement
1213 Tree.SubElement(childnode1, theme[2], attributeDict)
1214 Tree.SubElement(childnode2, theme[2], attributeDict)
1215 # todo: check if it can be integrated in if
1216 elif theme[0] == "bordersettheme":
1217 ws = curTree.find("windowstyle")
1218 for bs in ws.findall(theme[2]):
1219 if bs.get("name") == "bsWindow":
1220 parentnode1.append(Tree.fromstring(Tree.tostring(bs)))
1221 parentnode2.append(Tree.fromstring(Tree.tostring(bs)))
1223 if bs.get("name") == "bsListboxEntry":
1224 parentnode1.append(Tree.fromstring(Tree.tostring(bs)))
1225 parentnode2.append(Tree.fromstring(Tree.tostring(bs)))
1226 elif theme[0] == "windowstylescrollbartheme":
1227 for wssb in curTree.findall("windowstylescrollbar"):
1228 if wssb.get("id") == "4":
1229 for sb in wssb.findall("*"):
1230 parentnode1.append(Tree.fromstring(Tree.tostring(sb)))
1231 parentnode2.append(Tree.fromstring(Tree.tostring(sb)))
1232 elif theme[0] == "layouttheme":
1233 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" />'))
1234 Tree.SubElement(childnode2, theme[2], {"name": "sample"})
1235 elif theme[0] == "pngtheme":
1236 parentnode1.append(Tree.Comment('Sample: name=path+png_name (root=skindir), argb=a:alpha r:red g:green b:blue'))
1237 parentnode1.append(Tree.Comment('<png name="design/progress.png" width="814" height="5" argb="#ff55a0ff" />'))
1238 parentnode2.append(Tree.Comment('<png name="design/progress.png" width="814" height="5" argb="#ffffa055" />'))
1241 screenthemes = Tree.SubElement(themes, "screenthemes")
1242 for screenname in screenList:
1243 screennode = Tree.SubElement(screenthemes, "screens", {"name": screenname })
1244 childnode1 = Tree.SubElement(screennode, "screentheme", {"name": "orginal", "value": "active"})
1245 childnode2 = Tree.SubElement(screennode, "screentheme", {"name": "orginal - work", "value": "inactive"})
1247 skinScreen = curTree.find("screen[@name='%s']" %(screenname))
1248 if skinScreen is not None:
1249 childnode1.append(Tree.fromstring(Tree.tostring(skinScreen)))
1250 childnode2.append(Tree.fromstring(Tree.tostring(skinScreen)))
1252 # displayscreenthemes
1253 if displayTag is not None:
1254 displayscreenthemes = Tree.SubElement(themes, displayTag)
1255 for displayscreenname in displayScreenList:
1256 displayscreennode = Tree.SubElement(displayscreenthemes, "screens", {"name": displayscreenname, "id": IdString})
1257 childnode1 = Tree.SubElement(displayscreennode, displayTag[:-1], {"name": "orginal", "value": "active"})
1258 childnode2 = Tree.SubElement(displayscreennode, displayTag[:-1], {"name": "orginal - work", "value": "inactive"})
1259 skinScreen = curTree.find("screen[@name='%s'][@id='%s']" %(displayscreenname, IdString))
1260 if skinScreen is not None:
1261 childnode1.append(Tree.fromstring(Tree.tostring(skinScreen)))
1262 childnode2.append(Tree.fromstring(Tree.tostring(skinScreen)))
1265 XMLindent(themes, 0)
1268 themexml = open(MerlinSkinThemes.selThemeFile, "w")
1269 themexml.write(Tree.tostring(themes))
1272 self.updateSkinList()
1274 def loadPreview(self):
1275 pngpath = resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/prev.png"
1277 if not fileExists(pngpath):
1278 pngpath = resolveFilename(SCOPE_PLUGINS) + "Extensions/MerlinSkinThemes/noprev.png"
1280 self["Preview"].instance.setPixmapFromFile(pngpath)
1283 if fileExists(MerlinSkinThemes.selSkinFile):
1284 xml = Tree.parse(MerlinSkinThemes.selSkinFile)
1285 if xml.find("screen[@name='MerlinSkinThemes']"):
1286 MSTFixbox = self.session.openWithCallback(self.MSTScrFix,MessageBox,_("Delete screen to fix new MST version?"), MessageBox.TYPE_YESNO)
1287 MSTFixbox.setTitle(_("MST screen found"))
1289 self.session.open(MessageBox, _("No MST screen found in this skin.xml!"), MessageBox.TYPE_INFO)
1292 if self.curList == "SkinsList":
1294 _("[OK]\nswitch to themes/designs config screen for selected skin\n\n" +
1295 "[create themes] and [delete]\ntakes some time - please wait\n\n" +
1296 '[menu]\nremove <screen name="MerlinSkinThemes"...> from selected skin.'
1297 "This can fix a greenscreen if skin is not up to date for MST.")
1300 elif self.curList == "ConfigList":
1302 _("[OK]\nswitch to skin selection screen\n\n" +
1303 "[apply themes] takes some time - please wait\n\n" +
1304 "[delete design]\ndelete selected design\n\n" +
1305 "[save as design]\nselected themes/screens stored in new design\n\n" +
1306 "choose Design: -none-\nto reset themes to active settings/themes")
1309 self.session.open(MessageBox, HelpText, MessageBox.TYPE_INFO, title=_("MerlinSkinThemes - Help"))
1311 def ImageInfo(self):
1312 InfoText = "Enigma: " + E2ver + " - "
1315 InfoText += "ARM64: " + _("Yes") + " - "
1318 InfoText += "ARM: " + _("Yes") + " - "
1321 InfoText += "MIPSEL: " + _("Yes") + " - "
1324 InfoText += "Merlin: " + _("Yes") + " - "
1326 InfoText += "Merlin: " + _("No") + " - "
1329 InfoText += "GP3: " + GP3ver + " - "
1331 InfoText += "GP3: " + _("No") + " - "
1334 InfoText += "GP4: " + GP4ver
1336 InfoText += "GP4: " + _("No")
1338 self["ImageInfo"].setText(InfoText)
1340 def CopyrightInfo(self):
1343 curSkin = Tree.parse(MerlinSkinThemes.selSkinFile)
1344 rootSkin = curSkin.getroot()
1345 if rootSkin.find("copyright") is not None:
1346 copyright = rootSkin.find("copyright")
1347 if copyright.find("orginal") is not None:
1348 org = copyright.find("orginal")
1350 oAuthor = org.get("author")
1353 oVersion = org.get("version")
1354 if oVersion is None:
1356 oName = org.get("name")
1359 oSupport = org.get("supporturl")
1360 if oSupport is None:
1362 oLicense = org.get("license")
1363 if oLicense is None:
1367 "Skin " + oName + " by " + oAuthor + " - Version " + oVersion + " - " + oSupport + "\n\n" +
1368 "License:\n" + oLicense
1373 _("Skin ORGINAL - No info available")
1376 if copyright.find("mod") is not None:
1377 mod = copyright.find("mod")
1379 mAuthor = mod.get("author")
1382 mVersion = mod.get("version")
1383 if mVersion is None:
1385 mName = mod.get("name")
1388 mSupport = mod.get("supporturl")
1389 if mSupport is None:
1393 "Mod:\nSkin " + mName + " by " + mAuthor + " - Version " + mVersion + " - " + mSupport
1398 _("Skin MOD - No info available")
1401 InfoText = OrgText + "\n\n" + ModText
1404 InfoText = _("No copyright info available")
1406 #self.session.open(MessageBox, InfoText, MessageBox.TYPE_INFO, title="About Skin - " + MerlinSkinThemes.selSkinName)
1408 self["SkinCopyright"].setText(InfoText)
1410 def rgb2hex(self, r, g, b):
1411 return "#%02X%02X%02X" % (r,g,b)
1413 def hex2rgb(self, value):
1414 value = value.lstrip('#')
1416 return tuple(int(value[i:i+lv/3], 16) for i in range(0, lv, lv/3))
1418 def argb2hex(self, a, r, g, b):
1419 return "#%02X%02X%02X%02X" % (a,r,g,b)
1422 if config.plugins.MerlinSkinThemes.ShowPrevPNG.value == "1":
1423 config.plugins.MerlinSkinThemes.ShowPrevPNG.value = "0"
1424 self.session.open(MessageBox, _("Show prev.png - ") + _("Off"), MessageBox.TYPE_INFO, timeout=3)
1425 self["Preview"].hide()
1427 config.plugins.MerlinSkinThemes.ShowPrevPNG.value = "1"
1428 self.session.open(MessageBox, _("Show prev.png - ") + _("On"), MessageBox.TYPE_INFO, timeout=3)
1430 self["Preview"].show()
1432 def delSkinDir(self):
1433 print "[MST] Delete: %s" % resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/"
1434 shutil.rmtree(resolveFilename(SCOPE_SKIN) + MerlinSkinThemes.selSkinName + "/")
1435 self.updateSkinList()
1437 def restartGUI(self, answer):
1440 self.session.open(TryQuitMainloop, 3)
1445 restartbox = self.session.openWithCallback(self.restartGUI,MessageBox,_("Do you want to Restart the GUI now to apply new skin settings?"), MessageBox.TYPE_YESNO)
1446 restartbox.setTitle(_("Restart GUI now?"))
1448 def exit(self, cancel=True):
1449 print '[MST] closing'
1450 self["SkinsList"].onSelectionChanged.remove(self.changedSkinsList)
1452 # exit means settings must not be stored
1453 config.plugins.MerlinSkinThemes.Skin.cancel()
1454 config.plugins.MerlinSkinThemes.selSkin.cancel()
1455 config.plugins.MerlinSkinThemes.ShowPrevPNG.cancel()
1456 config.plugins.MerlinSkinThemes.CornerRadius.cancel()
1457 config.plugins.MerlinSkinThemes.applied.cancel()
1458 if "Designs" in config.plugins.MerlinSkinThemes.dict():
1459 for key in config.plugins.MerlinSkinThemes.Designs:
1460 config.plugins.MerlinSkinThemes.Designs[key].cancel()
1461 if "Themes" in config.plugins.MerlinSkinThemes.dict():
1462 for key in config.plugins.MerlinSkinThemes.Themes:
1463 config.plugins.MerlinSkinThemes.Themes[key].cancel()
1464 if "Screens" in config.plugins.MerlinSkinThemes.dict():
1465 for key in config.plugins.MerlinSkinThemes.Screens:
1466 config.plugins.MerlinSkinThemes.Screens[key].cancel()
1467 if "DisplayScreens" in config.plugins.MerlinSkinThemes.dict():
1468 for key in config.plugins.MerlinSkinThemes.DisplayScreens:
1469 config.plugins.MerlinSkinThemes.DisplayScreens[key].cancel()
1472 def main(session, **kwargs):
1473 session.open(MerlinSkinThemes)
1475 def Plugins(path,**kwargs):
1476 list = [PluginDescriptor(name = "MerlinSkinThemes", description = "MerlinSkinThemes", where = PluginDescriptor.WHERE_PLUGINMENU, icon = "plugin.png", fnc = main)]
1479 class MerlinSkinThemesConfig(Screen, HelpableScreen, ConfigListScreen):
1481 <screen position="center,center" size="600,200" title="Merlin Skin Themes - Config" backgroundColor="#00808080" >
1482 <widget name="config" position="10,10" size="580,100" scrollbarMode="showOnDemand" zPosition="1" />
1483 <widget name="key_red" position="10,150" size="200,40" valign="center" halign="center" zPosition="3" transparent="1" font="Regular;24" />
1484 <widget name="key_green" position="390,150" size="200,40" valign="center" halign="center" zPosition="3" transparent="1" font="Regular;24" />
1485 <ePixmap name="red" position="10,150" zPosition="1" size="200,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="blend" />
1486 <ePixmap name="green" position="390,150" zPosition="1" size="200,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="blend" />
1489 def __init__(self, session):
1490 Screen.__init__(self, session)
1491 HelpableScreen.__init__(self)
1493 self["key_red"] = Button(_("Exit"))
1494 self["key_green"] = Button(_("Save"))
1496 self["ColorActions"] = HelpableActionMap(self, "ColorActions",
1498 "red": (self.closePlugin, _("Close plugin")),
1499 "green": (self.saveSettings,_("Save settings")),
1502 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
1504 "ok": (self.saveSettings, _("Save settings")),
1505 "cancel": (self.closePlugin, _("Close plugin")),
1509 self.list.append(getConfigListEntry(_("Rebuild skin on boot"), config.plugins.MerlinSkinThemes.rebuildSkinOnBoot))
1511 ConfigListScreen.__init__(self, self.list)
1513 self["config"].setList(self.list)
1515 def saveSettings(self):
1516 config.plugins.MerlinSkinThemes.rebuildSkinOnBoot.save()
1520 def closePlugin(self):
1521 config.plugins.MerlinSkinThemes.rebuildSkinOnBoot.cancel()
1525 # =================================================================================================
1527 class GetSkinsList(MenuList, MerlinSkinThemes):
1528 SKIN_COMPONENT_KEY = "MerlinSkinThemesList"
1529 SKIN_COMPONENT_DIR_WIDTH = "dirWidth"
1530 SKIN_COMPONENT_STATUS_WIDTH = "statusWidth"
1531 SKIN_COMPONENT_INFO_WIDTH = "infoWidth"
1533 def __init__(self, list, enableWrapAround = True):
1534 MenuList.__init__(self, list, enableWrapAround, eListboxPythonMultiContent)
1535 tlf = TemplatedListFonts()
1536 self.l.setFont(0, gFont(tlf.face(tlf.MEDIUM), tlf.size(tlf.MEDIUM)))
1537 self.l.setFont(1, gFont(tlf.face(tlf.SMALLER), tlf.size(tlf.SMALLER)))
1538 self.l.setItemHeight(componentSizes.itemHeight(self.SKIN_COMPONENT_KEY, 30))
1539 self.selectedIndex = 0
1541 def buildList(self):
1543 self.selectedIndex = 0
1545 sizes = componentSizes[GetSkinsList.SKIN_COMPONENT_KEY]
1546 configEntryHeight = sizes.get(componentSizes.ITEM_HEIGHT, 30)
1547 dirWidth = sizes.get(GetSkinsList.SKIN_COMPONENT_DIR_WIDTH, 310)
1548 statusWidth = sizes.get(GetSkinsList.SKIN_COMPONENT_STATUS_WIDTH, 205)
1549 infoWidth = sizes.get(GetSkinsList.SKIN_COMPONENT_INFO_WIDTH, 205)
1551 dirs = os.listdir(resolveFilename(SCOPE_SKIN))
1553 if os.path.isdir(resolveFilename(SCOPE_SKIN) + dir) is True:
1554 curSkinFile = resolveFilename(SCOPE_SKIN) + dir + "/skin.xml"
1555 curThemeFile = resolveFilename(SCOPE_SKIN) + dir + "/themes.xml"
1563 if fileExists(curSkinFile):
1566 if fileExists(curThemeFile):
1569 if skinxml or themexml:
1570 if skinxml is False:
1571 info = _("no skin.xml")
1573 if themexml is False:
1574 info = _("no themes.xml")
1577 status = _("active skin")
1581 (eListboxPythonMultiContent.TYPE_TEXT, 5, 0, dirWidth, configEntryHeight, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, dir),
1582 (eListboxPythonMultiContent.TYPE_TEXT, 5 + dirWidth, 0, statusWidth, configEntryHeight, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, status),
1583 (eListboxPythonMultiContent.TYPE_TEXT, 5 + dirWidth + statusWidth, 0, infoWidth, configEntryHeight, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, info),
1588 self.list = list.sort()
1589 for x in range(len(list)):
1590 if list[x][2][7] == _("active skin"):
1591 self.selectedIndex = x
1594 self.l.setList(list)
1596 # =================================================================================================
1598 class MyConfigSelection(ConfigSelection):
1600 if self._descr is not None:
1602 descr = self._descr = self.description[self.value]
1605 def getMulti(self, selected):
1606 if self._descr is not None:
1609 descr = self._descr = self.description[self.value]
1611 return ("text", descr)
1612 return ("text", descr)