1 from Tools.Profile import profile
2 profile("LOAD:ElementTree")
3 import xml.etree.cElementTree
6 profile("LOAD:enigma_skin")
7 from enigma import eSize, ePoint, gFont, eWindow, eLabel, ePixmap, eWindowStyleManager, \
8 addFont, gRGB, eWindowStyleSkinned
9 from Components.config import ConfigSubsection, ConfigText, config
10 from Components.Converter.Converter import Converter
11 from Components.Sources.Source import Source, ObsoleteSource
12 from Tools.Directories import resolveFilename, SCOPE_SKIN, SCOPE_SKIN_IMAGE, SCOPE_FONTS, SCOPE_CURRENT_SKIN, SCOPE_CONFIG, fileExists
13 from Tools.Import import my_import
14 from Tools.LoadPixmap import LoadPixmap
19 "Body": ("Regular", 18, 22, 16),
20 "ChoiceList": ("Regular", 20, 24, 18),
26 print " " * i + str(x)
28 for n in x.childNodes:
33 class SkinError(Exception):
34 def __init__(self, message):
38 return "{%s}: %s" % (config.skin.primary_skin.value, self.msg)
42 def loadSkin(name, scope = SCOPE_SKIN):
44 filename = resolveFilename(scope, name)
45 mpath = path.dirname(filename) + "/"
46 dom_skins.append((mpath, xml.etree.cElementTree.parse(filename).getroot()))
48 # we do our best to always select the "right" value
49 # skins are loaded in order of priority: skin with
50 # highest priority is loaded last, usually the user-provided
53 # currently, loadSingleSkinData (colors, bordersets etc.)
54 # are applied one-after-each, in order of ascending priority.
55 # the dom_skin will keep all screens in descending priority,
56 # so the first screen found will be used.
58 # example: loadSkin("nemesis_greenline/skin.xml")
59 config.skin = ConfigSubsection()
60 config.skin.primary_skin = ConfigText(default = "skin.xml")
64 loadSkin('skin_user.xml', SCOPE_CONFIG)
65 except (SkinError, IOError, AssertionError), err:
66 print "not loading user skin: ", err
69 loadSkin(config.skin.primary_skin.value)
70 except (SkinError, IOError, AssertionError), err:
71 print "SKIN ERROR:", err
72 print "defaulting to standard skin..."
73 config.skin.primary_skin.value = 'skin.xml'
76 profile("LoadSkinDefault")
77 loadSkin('skin_default.xml')
78 profile("LoadSkinDefaultDone")
80 def parseCoordinate(str, e, size = 0):
98 val += e * int(str[l:sl-1]) / 100
100 val += int(str[l:sl])
105 def evalPos(pos, wsize, ssize, scale):
107 pos = (ssize - wsize) / 2
109 pos = int(pos) * scale[0] / scale[1]
112 def parsePosition(str, scale, desktop = None, size = None):
113 x, y = str.split(',')
117 if desktop is not None:
118 ssize = desktop.size().width(), desktop.size().height()
120 wsize = size.width(), size.height()
122 x = evalPos(x, wsize[0], ssize[0], scale[0])
123 y = evalPos(y, wsize[1], ssize[1], scale[1])
127 def parseSize(str, scale):
128 x, y = str.split(',')
129 return eSize(int(x) * scale[0][0] / scale[0][1], int(y) * scale[1][0] / scale[1][1])
131 def parseFont(s, scale):
137 name, size = s.split(';')
138 return gFont(name, int(size) * scale[0][0] / scale[0][1])
143 return colorNames[str]
145 raise SkinError("color '%s' must be #aarrggbb or valid named color" % (str))
146 return gRGB(int(str[1:], 0x10))
148 def collectAttributes(skinAttributes, node, context, skin_path_prefix=None, ignore=[]):
149 # walk all attributes
152 for attrib, value in node.items():
153 if attrib not in ignore:
154 if attrib in ("pixmap", "pointer", "seek_pointer", "backgroundPixmap", "selectionPixmap"):
155 value = resolveFilename(SCOPE_SKIN_IMAGE, value, path_prefix=skin_path_prefix)
157 # Bit of a hack this, really. When a window has a flag (e.g. wfNoBorder)
158 # it needs to be set at least before the size is set, in order for the
159 # window dimensions to be calculated correctly in all situations.
160 # If wfNoBorder is applied after the size has been set, the window will fail to clear the title area.
161 # Similar situation for a scrollbar in a listbox; when the scrollbar setting is applied after
162 # the size, a scrollbar will not be shown until the selection moves for the first time
165 size = value.encode("utf-8")
166 elif attrib == 'position':
167 pos = value.encode("utf-8")
169 skinAttributes.append((attrib, value.encode("utf-8")))
172 pos, size = context.parse(pos, size)
173 skinAttributes.append(('position', pos))
175 skinAttributes.append(('size', size))
177 def morphRcImagePath(value):
178 if value.startswith('/usr/share/enigma2') and path.basename(value) in ('rc.png', 'rcold.png'):
179 value = resolveFilename(SCOPE_SKIN, 'rc/' + 'rc_%d.png' % config.misc.rcused.value)
182 def loadPixmap(path, desktop):
184 option = path.find("#")
186 options = path[option+1:].split(',')
188 cached = "cached" in options
189 ptr = LoadPixmap(morphRcImagePath(path), desktop, cached)
191 raise SkinError("pixmap file %s not found!" % (path))
194 class AttributeParser:
195 def __init__(self, guiObject, desktop, scale = ((1,1),(1,1))):
196 self.guiObject = guiObject
197 self.desktop = desktop
199 def applyOne(self, attrib, value):
201 getattr(self, attrib)(value)
202 except AttributeError:
203 print "[Skin] Attribute not implemented:", attrib, "value:", value
204 except SkinError, ex:
205 print "[Skin] Error:", ex
206 def applyAll(self, attrs):
207 for attrib, value in attrs:
209 getattr(self, attrib)(value)
210 except AttributeError:
211 print "[Skin] Attribute not implemented:", attrib, "value:", value
212 except SkinError, ex:
213 print "[Skin] Error:", ex
214 def position(self, value):
215 if isinstance(value, tuple):
216 self.guiObject.move(ePoint(*value))
218 self.guiObject.move(parsePosition(value, self.scale, self.desktop, self.guiObject.csize()))
219 def size(self, value):
220 if isinstance(value, tuple):
221 self.guiObject.resize(eSize(*value))
223 self.guiObject.resize(parseSize(value, self.scale))
224 def animationPaused(self, value):
226 def animationPaused(self, value):
227 self.guiObject.setAnimationMode(
235 def title(self, value):
236 self.guiObject.setTitle(_(value))
237 def text(self, value):
238 self.guiObject.setText(_(value))
239 def font(self, value):
240 self.guiObject.setFont(parseFont(value, self.scale))
241 def zPosition(self, value):
242 self.guiObject.setZPosition(int(value))
243 def itemHeight(self, value):
244 self.guiObject.setItemHeight(int(value))
245 def pixmap(self, value):
246 ptr = loadPixmap(value, self.desktop)
247 self.guiObject.setPixmap(ptr)
248 def backgroundPixmap(self, value):
249 ptr = loadPixmap(value, self.desktop)
250 self.guiObject.setBackgroundPicture(ptr)
251 def selectionPixmap(self, value):
252 ptr = loadPixmap(value, self.desktop)
253 self.guiObject.setSelectionPicture(ptr)
254 def itemHeight(self, value):
255 self.guiObject.setItemHeight(int(value))
256 def alphatest(self, value):
257 self.guiObject.setAlphatest(
262 def scale(self, value):
263 self.guiObject.setScale(1)
264 def orientation(self, value):
266 self.guiObject.setOrientation(*
267 { "orVertical": (self.guiObject.orVertical, False),
268 "orTopToBottom": (self.guiObject.orVertical, False),
269 "orBottomToTop": (self.guiObject.orVertical, True),
270 "orHorizontal": (self.guiObject.orHorizontal, False),
271 "orLeftToRight": (self.guiObject.orHorizontal, False),
272 "orRightToLeft": (self.guiObject.orHorizontal, True),
275 print "oprientation must be either orVertical or orHorizontal!"
276 def valign(self, value):
278 self.guiObject.setVAlign(
279 { "top": self.guiObject.alignTop,
280 "center": self.guiObject.alignCenter,
281 "bottom": self.guiObject.alignBottom
284 print "valign must be either top, center or bottom!"
285 def halign(self, value):
287 self.guiObject.setHAlign(
288 { "left": self.guiObject.alignLeft,
289 "center": self.guiObject.alignCenter,
290 "right": self.guiObject.alignRight,
291 "block": self.guiObject.alignBlock
294 print "halign must be either left, center, right or block!"
295 def flags(self, value):
296 flags = value.split(',')
299 fv = eWindow.__dict__[f]
300 self.guiObject.setFlag(fv)
302 print "illegal flag %s!" % f
303 def backgroundColor(self, value):
304 self.guiObject.setBackgroundColor(parseColor(value))
305 def backgroundColorSelected(self, value):
306 self.guiObject.setBackgroundColorSelected(parseColor(value))
307 def foregroundColor(self, value):
308 self.guiObject.setForegroundColor(parseColor(value))
309 def foregroundColorSelected(self, value):
310 self.guiObject.setForegroundColorSelected(parseColor(value))
311 def shadowColor(self, value):
312 self.guiObject.setShadowColor(parseColor(value))
313 def selectionDisabled(self, value):
314 self.guiObject.setSelectionEnable(0)
315 def transparent(self, value):
316 self.guiObject.setTransparent(int(value))
317 def borderColor(self, value):
318 self.guiObject.setBorderColor(parseColor(value))
319 def borderWidth(self, value):
320 self.guiObject.setBorderWidth(int(value))
321 def scrollbarMode(self, value):
322 self.guiObject.setScrollbarMode(
323 { "showOnDemand": self.guiObject.showOnDemand,
324 "showAlways": self.guiObject.showAlways,
325 "showNever": self.guiObject.showNever
327 def enableWrapAround(self, value):
328 self.guiObject.setWrapAround(True)
329 def pointer(self, value):
330 (name, pos) = value.split(':')
331 pos = parsePosition(pos, self.scale)
332 ptr = loadPixmap(name, self.desktop)
333 self.guiObject.setPointer(0, ptr, pos)
334 def seek_pointer(self, value):
335 (name, pos) = value.split(':')
336 pos = parsePosition(pos, self.scale)
337 ptr = loadPixmap(name, self.desktop)
338 self.guiObject.setPointer(1, ptr, pos)
339 def shadowOffset(self, value):
340 self.guiObject.setShadowOffset(parsePosition(value, self.scale))
341 def noWrap(self, value):
342 self.guiObject.setNoWrap(1)
346 def applySingleAttribute(guiObject, desktop, attrib, value, scale = ((1,1),(1,1))):
347 # Someone still using applySingleAttribute?
348 AttributeParser(guiObject, desktop, scale).applyOne(attrib, value)
350 def applyAllAttributes(guiObject, desktop, attributes, scale):
351 AttributeParser(guiObject, desktop, scale).applyAll(attributes)
353 def loadSingleSkinData(desktop, skin, path_prefix):
354 """loads skin data like colors, windowstyle etc."""
355 assert skin.tag == "skin", "root element in skin must be 'skin'!"
357 #print "***SKIN: ", path_prefix
359 for c in skin.findall("output"):
360 id = c.attrib.get('id')
365 if id == 0: # framebuffer
366 for res in c.findall("resolution"):
367 get_attr = res.attrib.get
368 xres = get_attr("xres")
373 yres = get_attr("yres")
378 bpp = get_attr("bpp")
383 #print "Resolution:", xres,yres,bpp
384 from enigma import gMainDC
385 gMainDC.getInstance().setResolution(xres, yres)
386 desktop.resize(eSize(xres, yres))
388 # load palette (not yet implemented)
391 for c in skin.findall("colors"):
392 for color in c.findall("color"):
393 get_attr = color.attrib.get
394 name = get_attr("name")
395 color = get_attr("value")
397 colorNames[name] = parseColor(color)
398 #print "Color:", name, color
400 raise SkinError("need color and name, got %s %s" % (name, color))
402 for c in skin.findall("fonts"):
403 for font in c.findall("font"):
404 get_attr = font.attrib.get
405 filename = get_attr("filename", "<NONAME>")
406 name = get_attr("name", "Regular")
407 scale = get_attr("scale")
412 is_replacement = get_attr("replacement") and True or False
413 resolved_font = resolveFilename(SCOPE_FONTS, filename, path_prefix=path_prefix)
414 if not fileExists(resolved_font): #when font is not available look at current skin path
415 skin_path = resolveFilename(SCOPE_CURRENT_SKIN, filename)
416 if fileExists(skin_path):
417 resolved_font = skin_path
418 addFont(resolved_font, name, scale, is_replacement)
419 #print "Font: ", resolved_font, name, scale, is_replacement
421 for alias in c.findall("alias"):
422 get = alias.attrib.get
426 size = int(get("size"))
427 height = int(get("height", size)) # to be calculated some day
428 width = int(get("width", size))
430 fonts[name] = (font, size, height, width)
431 except Exception, ex:
432 print "[SKIN] bad font alias", ex
434 for c in skin.findall("parameters"):
435 for parameter in c.findall("parameter"):
436 get = parameter.attrib.get
440 parameters[name] = map(int, value.split(","))
441 except Exception, ex:
442 print "[SKIN] bad parameter", ex
444 for c in skin.findall("subtitles"):
445 from enigma import eWidget, eSubtitleWidget
446 scale = ((1,1),(1,1))
447 for substyle in c.findall("sub"):
448 get_attr = substyle.attrib.get
449 font = parseFont(get_attr("font"), scale)
450 col = get_attr("foregroundColor")
452 foregroundColor = parseColor(col)
455 foregroundColor = gRGB(0xFFFFFF)
457 col = get_attr("shadowColor")
459 shadowColor = parseColor(col)
461 shadowColor = gRGB(0)
462 shadowOffset = parsePosition(get_attr("shadowOffset"), scale)
463 face = eSubtitleWidget.__dict__[get_attr("name")]
464 eSubtitleWidget.setFontStyle(face, font, haveColor, foregroundColor, shadowColor, shadowOffset)
466 for windowstyle in skin.findall("windowstyle"):
467 style = eWindowStyleSkinned()
468 id = windowstyle.attrib.get("id")
473 #print "windowstyle:", id
476 font = gFont("Regular", 20)
477 offset = eSize(20, 5)
479 for title in windowstyle.findall("title"):
480 get_attr = title.attrib.get
481 offset = parseSize(get_attr("offset"), ((1,1),(1,1)))
482 font = parseFont(get_attr("font"), ((1,1),(1,1)))
484 style.setTitleFont(font);
485 style.setTitleOffset(offset)
486 #print " ", font, offset
488 for borderset in windowstyle.findall("borderset"):
489 bsName = str(borderset.attrib.get("name"))
490 for pixmap in borderset.findall("pixmap"):
491 get_attr = pixmap.attrib.get
492 bpName = get_attr("pos")
493 filename = get_attr("filename")
494 if filename and bpName:
495 png = loadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, filename, path_prefix=path_prefix), desktop)
496 style.setPixmap(eWindowStyleSkinned.__dict__[bsName], eWindowStyleSkinned.__dict__[bpName], png)
497 #print " borderset:", bpName, filename
499 for color in windowstyle.findall("color"):
500 get_attr = color.attrib.get
501 colorType = get_attr("name")
502 color = parseColor(get_attr("color"))
504 style.setColor(eWindowStyleSkinned.__dict__["col" + colorType], color)
506 raise SkinError("Unknown color %s" % (colorType))
509 #print " color:", type, color
511 x = eWindowStyleManager.getInstance()
512 x.setStyle(id, style)
517 def loadSkinData(desktop):
518 global dom_skins, dom_screens, display_skin_id
521 for (path, dom_skin) in skins:
522 loadSingleSkinData(desktop, dom_skin, path)
524 for elem in dom_skin:
525 if elem.tag == 'screen':
526 name = elem.attrib.get('name', None)
528 sid = elem.attrib.get('id', None)
529 if sid and (int(sid) != display_skin_id):
530 # not for this display
533 if name in dom_screens:
534 # Kill old versions, save memory
535 dom_screens[name][0].clear()
536 dom_screens[name] = (elem, path)
538 # without name, it's useless!
541 # non-screen element, no need for it any longer
543 # no longer needed, we know where the screens are now.
546 def lookupScreen(name, style_id):
547 if dom_screens.has_key(name):
548 elem, path = dom_screens[name]
549 screen_style_id = elem.attrib.get('id', '-1')
550 if screen_style_id == '-1' and name.find('ummary') > 0:
551 screen_style_id = '1'
552 if (style_id != 2 and int(screen_style_id) == -1) or int(screen_style_id) == style_id:
557 class additionalWidget:
560 # Class that makes a tuple look like something else. Some plugins just assume
561 # that size is a string and try to parse it. This class makes that work.
562 class SizeTuple(tuple):
563 def split(self, *args):
564 return (str(self[0]), str(self[1]))
565 def strip(self, *args):
566 return '%s,%s' % self
568 return '%s,%s' % self
571 def __init__(self, parent=None, pos=None, size=None):
572 if parent is not None:
574 pos, size = parent.parse(pos, size)
576 self.w, self.h = size
583 return "Context (%s,%s)+(%s,%s) " % (self.x, self.y, self.w, self.h)
584 def parse(self, pos, size):
586 pos = (self.x, self.y)
587 size = (self.w, self.h)
590 elif pos == "bottom":
591 w,h = size.split(',')
593 pos = (self.x, self.y + self.h - h)
597 w,h = size.split(',')
599 pos = (self.x, self.y)
604 w,h = size.split(',')
606 pos = (self.x, self.y)
611 w,h = size.split(',')
613 pos = (self.x + self.w - w, self.y)
617 size = size.split(',')
618 size = (parseCoordinate(size[0], self.w), parseCoordinate(size[1], self.h))
620 pos = (self.x + parseCoordinate(pos[0], self.w, size[0]), self.y + parseCoordinate(pos[1], self.h, size[1]))
621 return (SizeTuple(pos), SizeTuple(size))
623 class SkinContextStack(SkinContext):
624 # A context that stacks things instead of aligning them
625 def parse(self, pos, size):
627 pos = (self.x, self.y)
628 size = (self.w, self.h)
629 elif pos == "bottom":
630 w,h = size.split(',')
632 pos = (self.x, self.y + self.h - h)
635 w,h = size.split(',')
637 pos = (self.x, self.y)
640 w,h = size.split(',')
642 pos = (self.x, self.y)
645 w,h = size.split(',')
647 pos = (self.x + self.w - w, self.y)
650 size = size.split(',')
651 size = (parseCoordinate(size[0], self.w), parseCoordinate(size[1], self.h))
653 pos = (self.x + parseCoordinate(pos[0], self.w, size[0]), self.y + parseCoordinate(pos[1], self.h, size[1]))
654 return (SizeTuple(pos), SizeTuple(size))
656 def readSkin(screen, skin, names, desktop):
657 if not isinstance(names, list):
660 name = "<embedded-in-'%s'>" % screen.__class__.__name__
662 style_id = desktop.getStyleID();
664 # try all skins, first existing one have priority
666 myscreen, path = lookupScreen(n, style_id)
667 if myscreen is not None:
668 # use this name for debug output
672 # otherwise try embedded skin
674 myscreen = getattr(screen, "parsedSkin", None)
676 # try uncompiled embedded skin
677 if myscreen is None and getattr(screen, "skin", None):
678 print "Looking for embedded skin"
679 skin_tuple = screen.skin
680 if not isinstance(skin_tuple, tuple):
681 skin_tuple = (skin_tuple,)
682 for sskin in skin_tuple:
683 parsedSkin = xml.etree.cElementTree.fromstring(sskin)
684 screen_style_id = parsedSkin.attrib.get('id', '-1')
685 if (style_id != 2 and int(screen_style_id) == -1) or int(screen_style_id) == style_id:
686 myscreen = screen.parsedSkin = parsedSkin
689 #assert myscreen is not None, "no skin for screen '" + repr(names) + "' found!"
691 print "No skin to read..."
692 emptySkin = "<screen></screen>"
693 myscreen = screen.parsedSkin = xml.etree.cElementTree.fromstring(emptySkin)
695 screen.skinAttributes = [ ]
697 skin_path_prefix = getattr(screen, "skin_path", path)
699 # collectAttributes(screen.skinAttributes, myscreen, skin_path_prefix, ignore=["name"])
701 context = SkinContext()
705 context.w = s.width()
706 context.h = s.height()
708 collectAttributes(screen.skinAttributes, myscreen, context, skin_path_prefix, ignore=("name",))
709 context = SkinContext(context, myscreen.attrib.get('position'), myscreen.attrib.get('size'))
713 screen.additionalWidgets = [ ]
714 screen.renderer = [ ]
716 visited_components = set()
718 # now walk all widgets and stuff
719 def process_none(widget, context):
722 def process_widget(widget, context):
723 get_attr = widget.attrib.get
724 # ok, we either have 1:1-mapped widgets ('old style'), or 1:n-mapped
725 # widgets (source->renderer).
727 wname = get_attr('name')
728 wsource = get_attr('source')
730 if wname is None and wsource is None:
731 print "widget has no name and no source!"
735 #print "Widget name=", wname
736 visited_components.add(wname)
738 # get corresponding 'gui' object
740 attributes = screen[wname].skinAttributes = [ ]
742 raise SkinError("component with name '" + wname + "' was not found in skin of screen '" + name + "'!")
743 #print "WARNING: component with name '" + wname + "' was not found in skin of screen '" + name + "'!"
745 # assert screen[wname] is not Source
747 # and collect attributes for this
748 collectAttributes(attributes, widget, context, skin_path_prefix, ignore=['name'])
750 # get corresponding source
751 #print "Widget source=", wsource
753 while True: # until we found a non-obsolete source
755 # parse our current "wsource", which might specifiy a "related screen" before the dot,
756 # for example to reference a parent, global or session-global screen.
759 # resolve all path components
760 path = wsource.split('.')
762 scr = screen.getRelatedScreen(path[0])
766 raise SkinError("specified related screen '" + wsource + "' was not found in screen '" + name + "'!")
769 # resolve the source.
770 source = scr.get(path[0])
771 if isinstance(source, ObsoleteSource):
772 # however, if we found an "obsolete source", issue warning, and resolve the real source.
773 print "WARNING: SKIN '%s' USES OBSOLETE SOURCE '%s', USE '%s' INSTEAD!" % (name, wsource, source.new_source)
774 print "OBSOLETE SOURCE WILL BE REMOVED %s, PLEASE UPDATE!" % (source.removal_date)
775 if source.description:
776 print source.description
778 wsource = source.new_source
780 # otherwise, use that source.
784 raise SkinError("source '" + wsource + "' was not found in screen '" + name + "'!")
786 wrender = get_attr('render')
789 raise SkinError("you must define a renderer with render= for source '%s'" % (wsource))
791 for converter in widget.findall("convert"):
792 ctype = converter.get('type')
793 assert ctype, "'convert'-tag needs a 'type'-attribute"
794 #print "Converter:", ctype
796 parms = converter.text.strip()
799 #print "Params:", parms
800 converter_class = my_import('.'.join(("Components", "Converter", ctype))).__dict__.get(ctype)
804 for i in source.downstream_elements:
805 if isinstance(i, converter_class) and i.converter_arguments == parms:
809 print "allocating new converter!"
810 c = converter_class(parms)
813 print "reused converter!"
817 renderer_class = my_import('.'.join(("Components", "Renderer", wrender))).__dict__.get(wrender)
819 renderer = renderer_class() # instantiate renderer
821 renderer.connect(source) # connect to source
822 attributes = renderer.skinAttributes = [ ]
823 collectAttributes(attributes, widget, context, skin_path_prefix, ignore=['render', 'source'])
825 screen.renderer.append(renderer)
827 def process_applet(widget, context):
829 codeText = widget.text.strip()
835 widgetType = widget.attrib.get('type')
837 code = compile(codeText, "skin applet", "exec")
839 if widgetType == "onLayoutFinish":
840 screen.onLayoutFinish.append(code)
841 #print "onLayoutFinish = ", codeText
843 raise SkinError("applet type '%s' unknown!" % widgetType)
844 #print "applet type '%s' unknown!" % type
846 def process_elabel(widget, context):
847 w = additionalWidget()
849 w.skinAttributes = [ ]
850 collectAttributes(w.skinAttributes, widget, context, skin_path_prefix, ignore=['name'])
851 screen.additionalWidgets.append(w)
853 def process_epixmap(widget, context):
854 w = additionalWidget()
856 w.skinAttributes = [ ]
857 collectAttributes(w.skinAttributes, widget, context, skin_path_prefix, ignore=['name'])
858 screen.additionalWidgets.append(w)
860 def process_screen(widget, context):
861 for w in widget.findall("widget"):
862 process_widget(w, context)
864 for w in widget.getchildren():
865 if w.tag == "widget":
868 p = processors.get(w.tag, process_none)
871 def process_panel(widget, context):
872 n = widget.attrib.get('name')
875 s = dom_screens.get(n, None)
877 print "[SKIN] Unable to find screen '%s' referred in screen '%s'" % (n, name)
879 process_screen(s[0], context)
881 layout = widget.attrib.get('layout')
882 if layout == 'stack':
883 cc = SkinContextStack
887 c = cc(context, widget.attrib.get('position'), widget.attrib.get('size'))
888 except Exception, ex:
889 raise SkinError("Failed to create skincontext (%s,%s) in %s: %s" % (widget.attrib.get('position'), widget.attrib.get('size'), context, ex) )
891 process_screen(widget, c)
895 "widget": process_widget,
896 "applet": process_applet,
897 "eLabel": process_elabel,
898 "ePixmap": process_epixmap,
899 "panel": process_panel
903 context.x = 0 # reset offsets, all components are relative to screen
904 context.y = 0 # coordinates.
905 process_screen(myscreen, context)
907 print "[Skin] SKIN ERROR:", e
909 from Components.GUIComponent import GUIComponent
910 nonvisited_components = [x for x in set(screen.keys()) - visited_components if isinstance(x, GUIComponent)]
911 assert not nonvisited_components, "the following components in %s don't have a skin entry: %s" % (name, ', '.join(nonvisited_components))
912 # This may look pointless, but it unbinds 'screen' from the nested scope. A better
913 # solution is to avoid the nested scope above and use the context object to pass
916 visited_components = None