X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/c8fb1149d64afb4faad18e66ee9f9f5e97eb067f..7b0d371a7bbfb9e8d624eec9ed97e9a835f75ca7:/skin.py diff --git a/skin.py b/skin.py index 5a6408f3..fc0360c5 100644 --- a/skin.py +++ b/skin.py @@ -1,8 +1,14 @@ -from enigma import * import xml.dom.minidom -from xml.dom import EMPTY_NAMESPACE +from os import path + +from enigma import eSize, ePoint, gFont, eWindow, eLabel, ePixmap, eWindowStyleManager, \ + loadPNG, addFont, gRGB, eWindowStyleSkinned + +from Components.config import ConfigSubsection, ConfigText, config +from Components.Converter.Converter import Converter +from Components.Sources.Source import Source, ObsoleteSource +from Tools.Directories import resolveFilename, SCOPE_SKIN, SCOPE_SKIN_IMAGE, SCOPE_FONTS from Tools.Import import my_import -import os from Tools.XMLTools import elementsWithTag, mergeText @@ -16,8 +22,6 @@ def dump(x, i=0): except: None -from Tools.Directories import resolveFilename, SCOPE_SKIN, SCOPE_SKIN_IMAGE, SCOPE_FONTS - class SkinError(Exception): def __init__(self, message): self.message = message @@ -30,8 +34,8 @@ dom_skins = [ ] def loadSkin(name): # read the skin filename = resolveFilename(SCOPE_SKIN, name) - path = os.path.dirname(filename) + "/" - dom_skins.append((path, xml.dom.minidom.parse(filename))) + mpath = path.dirname(filename) + "/" + dom_skins.append((mpath, xml.dom.minidom.parse(filename))) # we do our best to always select the "right" value # skins are loaded in order of priority: skin with @@ -44,7 +48,15 @@ def loadSkin(name): # so the first screen found will be used. # example: loadSkin("nemesis_greenline/skin.xml") -loadSkin('skin.xml') +config.skin = ConfigSubsection() +config.skin.primary_skin = ConfigText(default = "skin.xml") + +try: + loadSkin(config.skin.primary_skin.value) +except (SkinError, IOError, AssertionError), err: + print "SKIN ERROR:", err + print "defaulting to standard skin..." + loadSkin('skin.xml') loadSkin('skin_default.xml') def parsePosition(str): @@ -77,7 +89,7 @@ def collectAttributes(skinAttributes, node, skin_path_prefix=None, ignore=[]): # TODO: localization? as in e1? value = a.value.encode("utf-8") - if attrib in ["pixmap", "pointer"]: + if attrib in ["pixmap", "pointer", "seek_pointer", "backgroundPixmap", "selectionPixmap"]: value = resolveFilename(SCOPE_SKIN_IMAGE, value, path_prefix=skin_path_prefix) if attrib not in ignore: @@ -99,16 +111,20 @@ def applySingleAttribute(guiObject, desktop, attrib, value): elif attrib == 'title': guiObject.setTitle(_(value)) elif attrib == 'text': - guiObject.setText(value) + guiObject.setText(_(value)) elif attrib == 'font': guiObject.setFont(parseFont(value)) elif attrib == 'zPosition': guiObject.setZPosition(int(value)) - elif attrib == "pixmap": + elif attrib in ["pixmap", "backgroundPixmap", "selectionPixmap"]: ptr = loadPixmap(value) # this should already have been filename-resolved. - # that __deref__ still scares me! - desktop.makeCompatiblePixmap(ptr.__deref__()) - guiObject.setPixmap(ptr.__deref__()) + desktop.makeCompatiblePixmap(ptr) + if attrib == "pixmap": + guiObject.setPixmap(ptr) + elif attrib == "backgroundPixmap": + guiObject.setBackgroundPicture(ptr) + elif attrib == "selectionPixmap": + guiObject.setSelectionPicture(ptr) # guiObject.setPixmapFromFile(value) elif attrib == "alphatest": # used by ePixmap guiObject.setAlphatest( @@ -172,14 +188,16 @@ def applySingleAttribute(guiObject, desktop, attrib, value): }[value]) elif attrib == "enableWrapAround": guiObject.setWrapAround(True) - elif attrib == "pointer": + elif attrib == "pointer" or attrib == "seek_pointer": (name, pos) = value.split(':') pos = parsePosition(pos) ptr = loadPixmap(name) - desktop.makeCompatiblePixmap(ptr.__deref__()) - guiObject.setPointer(ptr.__deref__(), pos) + desktop.makeCompatiblePixmap(ptr) + guiObject.setPointer({"pointer": 0, "seek_pointer": 1}[attrib], ptr, pos) elif attrib == 'shadowOffset': guiObject.setShadowOffset(parsePosition(value)) + elif attrib == 'noWrap': + guiObject.setNoWrap(1) else: raise "unsupported attribute " + attrib + "=" + value except int: @@ -216,6 +234,7 @@ def loadSingleSkinData(desktop, dom_skin, path_prefix): for windowstyle in elementsWithTag(skin.childNodes, "windowstyle"): style = eWindowStyleSkinned() + id = int(windowstyle.getAttribute("id") or "0") # defaults font = gFont("Regular", 20) @@ -237,8 +256,8 @@ def loadSingleSkinData(desktop, dom_skin, path_prefix): png = loadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, filename, path_prefix=path_prefix)) # adapt palette - desktop.makeCompatiblePixmap(png.__deref__()) - style.setPixmap(eWindowStyleSkinned.__dict__[bsName], eWindowStyleSkinned.__dict__[bpName], png.__deref__()) + desktop.makeCompatiblePixmap(png) + style.setPixmap(eWindowStyleSkinned.__dict__[bsName], eWindowStyleSkinned.__dict__[bpName], png) for color in elementsWithTag(windowstyle.childNodes, "color"): type = str(color.getAttribute("name")) @@ -249,9 +268,8 @@ def loadSingleSkinData(desktop, dom_skin, path_prefix): except: raise ("Unknown color %s" % (type)) - x = eWindowStyleManagerPtr() - eWindowStyleManager.getInstance(x) - x.setStyle(style) + x = eWindowStyleManager.getInstance() + x.setStyle(id, style) def loadSkinData(desktop): skins = dom_skins[:] @@ -268,17 +286,28 @@ def lookupScreen(name): return x, path return None, None -def readSkin(screen, skin, name, desktop): - myscreen, path = lookupScreen(name) - +def readSkin(screen, skin, names, desktop): + if not isinstance(names, list): + names = [names] + + name = "" % screen.__class__.__name__ + + # try all skins, first existing one have priority + for n in names: + myscreen, path = lookupScreen(n) + if myscreen is not None: + # use this name for debug output + name = n + break + # otherwise try embedded skin myscreen = myscreen or getattr(screen, "parsedSkin", None) - + # try uncompiled embedded skin if myscreen is None and getattr(screen, "skin", None): myscreen = screen.parsedSkin = xml.dom.minidom.parseString(screen.skin).childNodes[0] - - assert myscreen is not None, "no skin for screen '" + name + "' found!" + + assert myscreen is not None, "no skin for screen '" + repr(names) + "' found!" screen.skinAttributes = [ ] @@ -289,6 +318,8 @@ def readSkin(screen, skin, name, desktop): screen.additionalWidgets = [ ] screen.renderer = [ ] + visited_components = set() + # now walk all widgets for widget in elementsWithTag(myscreen.childNodes, "widget"): # ok, we either have 1:1-mapped widgets ('old style'), or 1:n-mapped @@ -297,11 +328,14 @@ def readSkin(screen, skin, name, desktop): wname = widget.getAttribute('name') wsource = widget.getAttribute('source') + if wname is None and wsource is None: print "widget has no name and no source!" continue if wname: + visited_components.add(wname) + # get corresponding 'gui' object try: attributes = screen[wname].skinAttributes = [ ] @@ -309,12 +343,42 @@ def readSkin(screen, skin, name, desktop): raise SkinError("component with name '" + wname + "' was not found in skin of screen '" + name + "'!") # assert screen[wname] is not Source - + # and collect attributes for this collectAttributes(attributes, widget, skin_path_prefix, ignore=['name']) elif wsource: # get corresponding source - source = screen.get(wsource) + + while True: # until we found a non-obsolete source + + # parse our current "wsource", which might specifiy a "related screen" before the dot, + # for example to reference a parent, global or session-global screen. + scr = screen + + # resolve all path components + path = wsource.split('.') + while len(path) > 1: + scr = screen.getRelatedScreen(path[0]) + if scr is None: + print wsource + print name + raise SkinError("specified related screen '" + wsource + "' was not found in screen '" + name + "'!") + path = path[1:] + + # resolve the source. + source = scr.get(path[0]) + if isinstance(source, ObsoleteSource): + # however, if we found an "obsolete source", issue warning, and resolve the real source. + print "WARNING: SKIN '%s' USES OBSOLETE SOURCE '%s', USE '%s' INSTEAD!" % (name, wsource, source.new_source) + print "OBSOLETE SOURCE WILL BE REMOVED %s, PLEASE UPDATE!" % (source.removal_date) + if source.description: + print source.description + + wsource = source.new_source + else: + # otherwise, use that source. + break + if source is None: raise SkinError("source '" + wsource + "' was not found in screen '" + name + "'!") @@ -325,12 +389,23 @@ def readSkin(screen, skin, name, desktop): for converter in elementsWithTag(widget.childNodes, "convert"): ctype = converter.getAttribute('type') - assert ctype - converter_class = my_import('.'.join(["Components", "Converter", ctype])).__dict__.get(ctype) + assert ctype, "'convert'-tag needs a 'type'-attribute" parms = mergeText(converter.childNodes).strip() - c = converter_class(parms) + converter_class = my_import('.'.join(["Components", "Converter", ctype])).__dict__.get(ctype) + + c = None - c.connect(source) + for i in source.downstream_elements: + if isinstance(i, converter_class) and i.converter_arguments == parms: + c = i + + if c is None: + print "allocating new converter!" + c = converter_class(parms) + c.connect(source) + else: + print "reused converter!" + source = c renderer_class = my_import('.'.join(["Components", "Renderer", wrender])).__dict__.get(wrender) @@ -343,6 +418,11 @@ def readSkin(screen, skin, name, desktop): screen.renderer.append(renderer) + from Components.GUIComponent import GUIComponent + nonvisited_components = [x for x in set(screen.keys()) - visited_components if isinstance(x, GUIComponent)] + + assert not nonvisited_components, "the following components in %s don't have a skin entry: %s" % (name, ', '.join(nonvisited_components)) + # now walk additional objects for widget in elementsWithTag(myscreen.childNodes, lambda x: x != "widget"): if widget.tagName == "applet":