Merge pull request #3882 from jmarshallnz/deps_first_please
[vuplus_xbmc] / xbmc / guilib / GUIControlFactory.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "system.h"
22 #include "GUIControlFactory.h"
23 #include "LocalizeStrings.h"
24 #include "GUIButtonControl.h"
25 #include "GUIRadioButtonControl.h"
26 #include "GUISpinControl.h"
27 #include "GUIRSSControl.h"
28 #include "GUIImage.h"
29 #include "GUIBorderedImage.h"
30 #include "GUILabelControl.h"
31 #include "GUIEditControl.h"
32 #include "GUIFadeLabelControl.h"
33 #include "GUICheckMarkControl.h"
34 #include "GUIToggleButtonControl.h"
35 #include "GUITextBox.h"
36 #include "GUIVideoControl.h"
37 #include "GUIProgressControl.h"
38 #include "GUISliderControl.h"
39 #include "GUISelectButtonControl.h"
40 #include "GUIMoverControl.h"
41 #include "GUIResizeControl.h"
42 #include "GUISpinControlEx.h"
43 #include "GUIVisualisationControl.h"
44 #include "GUISettingsSliderControl.h"
45 #include "GUIMultiImage.h"
46 #include "GUIControlGroup.h"
47 #include "GUIControlGroupList.h"
48 #include "GUIScrollBarControl.h"
49 #include "GUIListContainer.h"
50 #include "GUIFixedListContainer.h"
51 #include "GUIWrappingListContainer.h"
52 #include "epg/GUIEPGGridContainer.h"
53 #include "GUIPanelContainer.h"
54 #include "GUIMultiSelectText.h"
55 #include "GUIListLabel.h"
56 #include "GUIListGroup.h"
57 #include "GUIInfoManager.h"
58 #include "utils/CharsetConverter.h"
59 #include "utils/log.h"
60 #include "utils/XMLUtils.h"
61 #include "GUIFontManager.h"
62 #include "GUIColorManager.h"
63 #include "utils/RssManager.h"
64 #include "utils/StringUtils.h"
65 #include "GUIAction.h"
66 #include "utils/RssReader.h"
67
68 using namespace std;
69 using namespace EPG;
70
71 typedef struct
72 {
73   const char* name;
74   CGUIControl::GUICONTROLTYPES type;
75 } ControlMapping;
76
77 static const ControlMapping controls[] =
78    {{"button",            CGUIControl::GUICONTROL_BUTTON},
79     {"checkmark",         CGUIControl::GUICONTROL_CHECKMARK},
80     {"fadelabel",         CGUIControl::GUICONTROL_FADELABEL},
81     {"image",             CGUIControl::GUICONTROL_IMAGE},
82     {"largeimage",        CGUIControl::GUICONTROL_IMAGE},
83     {"image",             CGUIControl::GUICONTROL_BORDEREDIMAGE},
84     {"label",             CGUIControl::GUICONTROL_LABEL},
85     {"label",             CGUIControl::GUICONTROL_LISTLABEL},
86     {"group",             CGUIControl::GUICONTROL_GROUP},
87     {"group",             CGUIControl::GUICONTROL_LISTGROUP},
88     {"progress",          CGUIControl::GUICONTROL_PROGRESS},
89     {"radiobutton",       CGUIControl::GUICONTROL_RADIO},
90     {"rss",               CGUIControl::GUICONTROL_RSS},
91     {"selectbutton",      CGUIControl::GUICONTROL_SELECTBUTTON},
92     {"slider",            CGUIControl::GUICONTROL_SLIDER},
93     {"sliderex",          CGUIControl::GUICONTROL_SETTINGS_SLIDER},
94     {"spincontrol",       CGUIControl::GUICONTROL_SPIN},
95     {"spincontrolex",     CGUIControl::GUICONTROL_SPINEX},
96     {"textbox",           CGUIControl::GUICONTROL_TEXTBOX},
97     {"togglebutton",      CGUIControl::GUICONTROL_TOGGLEBUTTON},
98     {"videowindow",       CGUIControl::GUICONTROL_VIDEO},
99     {"mover",             CGUIControl::GUICONTROL_MOVER},
100     {"resize",            CGUIControl::GUICONTROL_RESIZE},
101     {"edit",              CGUIControl::GUICONTROL_EDIT},
102     {"visualisation",     CGUIControl::GUICONTROL_VISUALISATION},
103     {"karvisualisation",  CGUIControl::GUICONTROL_VISUALISATION},
104     {"renderaddon",       CGUIControl::GUICONTROL_RENDERADDON},
105     {"multiimage",        CGUIControl::GUICONTROL_MULTI_IMAGE},
106     {"grouplist",         CGUIControl::GUICONTROL_GROUPLIST},
107     {"scrollbar",         CGUIControl::GUICONTROL_SCROLLBAR},
108     {"multiselect",       CGUIControl::GUICONTROL_MULTISELECT},
109     {"list",              CGUIControl::GUICONTAINER_LIST},
110     {"wraplist",          CGUIControl::GUICONTAINER_WRAPLIST},
111     {"fixedlist",         CGUIControl::GUICONTAINER_FIXEDLIST},
112     {"epggrid",           CGUIControl::GUICONTAINER_EPGGRID},
113     {"panel",             CGUIControl::GUICONTAINER_PANEL}};
114
115 CGUIControl::GUICONTROLTYPES CGUIControlFactory::TranslateControlType(const CStdString &type)
116 {
117   for (unsigned int i = 0; i < sizeof(controls) / sizeof(controls[0]); ++i)
118     if (StringUtils::EqualsNoCase(type, controls[i].name))
119       return controls[i].type;
120   return CGUIControl::GUICONTROL_UNKNOWN;
121 }
122
123 CStdString CGUIControlFactory::TranslateControlType(CGUIControl::GUICONTROLTYPES type)
124 {
125   for (unsigned int i = 0; i < sizeof(controls) / sizeof(controls[0]); ++i)
126     if (type == controls[i].type)
127       return controls[i].name;
128   return "";
129 }
130
131 CGUIControlFactory::CGUIControlFactory(void)
132 {}
133
134 CGUIControlFactory::~CGUIControlFactory(void)
135 {}
136
137 bool CGUIControlFactory::GetIntRange(const TiXmlNode* pRootNode, const char* strTag, int& iMinValue, int& iMaxValue, int& iIntervalValue)
138 {
139   const TiXmlNode* pNode = pRootNode->FirstChild(strTag);
140   if (!pNode || !pNode->FirstChild()) return false;
141   iMinValue = atoi(pNode->FirstChild()->Value());
142   const char* maxValue = strchr(pNode->FirstChild()->Value(), ',');
143   if (maxValue)
144   {
145     maxValue++;
146     iMaxValue = atoi(maxValue);
147
148     const char* intervalValue = strchr(maxValue, ',');
149     if (intervalValue)
150     {
151       intervalValue++;
152       iIntervalValue = atoi(intervalValue);
153     }
154   }
155
156   return true;
157 }
158
159 bool CGUIControlFactory::GetFloatRange(const TiXmlNode* pRootNode, const char* strTag, float& fMinValue, float& fMaxValue, float& fIntervalValue)
160 {
161   const TiXmlNode* pNode = pRootNode->FirstChild(strTag);
162   if (!pNode || !pNode->FirstChild()) return false;
163   fMinValue = (float)atof(pNode->FirstChild()->Value());
164   const char* maxValue = strchr(pNode->FirstChild()->Value(), ',');
165   if (maxValue)
166   {
167     maxValue++;
168     fMaxValue = (float)atof(maxValue);
169
170     const char* intervalValue = strchr(maxValue, ',');
171     if (intervalValue)
172     {
173       intervalValue++;
174       fIntervalValue = (float)atof(intervalValue);
175     }
176   }
177
178   return true;
179 }
180
181 float CGUIControlFactory::ParsePosition(const char* pos, const float parentSize)
182 {
183   char* end = NULL;
184   float value = pos ? (float)strtod(pos, &end) : 0;
185   if (end)
186   {
187     if (*end == 'r')
188       value = parentSize - value;
189     else if (*end == '%')
190       value = value * parentSize / 100.0f;
191   }
192   return value;
193 }
194
195 bool CGUIControlFactory::GetPosition(const TiXmlNode *node, const char* strTag, const float parentSize, float& value)
196 {
197   const TiXmlElement* pNode = node->FirstChildElement(strTag);
198   if (!pNode || !pNode->FirstChild()) return false;
199
200   value = ParsePosition(pNode->FirstChild()->Value(), parentSize);
201   return true;
202 }
203
204 bool CGUIControlFactory::GetDimension(const TiXmlNode *pRootNode, const char* strTag, const float parentSize, float &value, float &min)
205 {
206   const TiXmlElement* pNode = pRootNode->FirstChildElement(strTag);
207   if (!pNode || !pNode->FirstChild()) return false;
208   if (0 == strnicmp("auto", pNode->FirstChild()->Value(), 4))
209   { // auto-width - at least min must be set
210     value = ParsePosition(pNode->Attribute("max"), parentSize);
211     min = ParsePosition(pNode->Attribute("min"), parentSize);
212     if (!min) min = 1;
213     return true;
214   }
215   value = (float)atof(pNode->FirstChild()->Value());
216   return true;
217 }
218
219 bool CGUIControlFactory::GetDimensions(const TiXmlNode *node, const char *leftTag, const char *rightTag, const char *centerLeftTag,
220                                        const char *centerRightTag, const char *widthTag, const float parentSize, float &left,
221                                        float &width, float &min_width)
222 {
223   float center = 0, right = 0;
224
225   // read from the XML
226   bool hasLeft = GetPosition(node, leftTag, parentSize, left);
227   bool hasCenter = GetPosition(node, centerLeftTag, parentSize, center);
228   if (!hasCenter && GetPosition(node, centerRightTag, parentSize, center))
229   {
230     center = parentSize - center;
231     hasCenter = true;
232   }
233   bool hasRight = false;
234   if (GetPosition(node, rightTag, parentSize, right))
235   {
236     right = parentSize - right;
237     hasRight = true;
238   }
239   bool hasWidth = GetDimension(node, widthTag, parentSize, width, min_width);
240
241   if (!hasLeft)
242   { // figure out position
243     if (hasCenter) // no left specified
244     {
245       if (hasWidth)
246       {
247         left = center - width/2;
248         hasLeft = true;
249       }
250       else
251       {
252         if (hasRight)
253         {
254           width = (right - center) * 2;
255           left = right - width;
256           hasLeft = true;
257         }
258       }
259     }
260     else if (hasRight) // no left or centre
261     {
262       if (hasWidth)
263       {
264         left = right - width;
265         hasLeft = true;
266       }
267     }
268   }
269   if (!hasWidth)
270   {
271     if (hasRight)
272     {
273       width = max(0.0f, right - left); // if left=0, this fills to size of parent
274       hasLeft = true;
275     }
276     else if (hasCenter)
277     {
278       if (hasLeft)
279       {
280         width = max(0.0f, (center - left) * 2);
281         hasWidth = true;
282       }
283       else if (center > 0 && center < parentSize)
284       { // centre given, so fill to edge of parent
285         width = max(0.0f, min(parentSize - center, center) * 2);
286         left = center - width/2;
287         hasLeft = hasWidth = true;
288       }
289     }
290     else if (hasLeft) // neither right nor center specified
291     {
292       width = max(0.0f, parentSize - left); // if left=0, this fills to parent
293     }
294   }
295   return hasLeft && hasWidth;
296 }
297
298 bool CGUIControlFactory::GetAspectRatio(const TiXmlNode* pRootNode, const char* strTag, CAspectRatio &aspect)
299 {
300   CStdString ratio;
301   const TiXmlElement *node = pRootNode->FirstChildElement(strTag);
302   if (!node || !node->FirstChild())
303     return false;
304
305   ratio = node->FirstChild()->Value();
306   if (StringUtils::EqualsNoCase(ratio, "keep")) aspect.ratio = CAspectRatio::AR_KEEP;
307   else if (StringUtils::EqualsNoCase(ratio, "scale")) aspect.ratio = CAspectRatio::AR_SCALE;
308   else if (StringUtils::EqualsNoCase(ratio, "center")) aspect.ratio = CAspectRatio::AR_CENTER;
309   else if (StringUtils::EqualsNoCase(ratio, "stretch")) aspect.ratio = CAspectRatio::AR_STRETCH;
310
311   const char *attribute = node->Attribute("align");
312   if (attribute)
313   {
314     CStdString align(attribute);
315     if (StringUtils::EqualsNoCase(align, "center")) aspect.align = ASPECT_ALIGN_CENTER | (aspect.align & ASPECT_ALIGNY_MASK);
316     else if (StringUtils::EqualsNoCase(align, "right")) aspect.align = ASPECT_ALIGN_RIGHT | (aspect.align & ASPECT_ALIGNY_MASK);
317     else if (StringUtils::EqualsNoCase(align, "left")) aspect.align = ASPECT_ALIGN_LEFT | (aspect.align & ASPECT_ALIGNY_MASK);
318   }
319   attribute = node->Attribute("aligny");
320   if (attribute)
321   {
322     CStdString align(attribute);
323     if (StringUtils::EqualsNoCase(align, "center")) aspect.align = ASPECT_ALIGNY_CENTER | (aspect.align & ASPECT_ALIGN_MASK);
324     else if (StringUtils::EqualsNoCase(align, "bottom")) aspect.align = ASPECT_ALIGNY_BOTTOM | (aspect.align & ASPECT_ALIGN_MASK);
325     else if (StringUtils::EqualsNoCase(align, "top")) aspect.align = ASPECT_ALIGNY_TOP | (aspect.align & ASPECT_ALIGN_MASK);
326   }
327   attribute = node->Attribute("scalediffuse");
328   if (attribute)
329   {
330     CStdString scale(attribute);
331     if (StringUtils::EqualsNoCase(scale, "true") || StringUtils::EqualsNoCase(scale, "yes"))
332       aspect.scaleDiffuse = true;
333     else
334       aspect.scaleDiffuse = false;
335   }
336   return true;
337 }
338
339 bool CGUIControlFactory::GetInfoTexture(const TiXmlNode* pRootNode, const char* strTag, CTextureInfo &image, CGUIInfoLabel &info, int parentID)
340 {
341   GetTexture(pRootNode, strTag, image);
342   image.filename = "";
343   GetInfoLabel(pRootNode, strTag, info, parentID);
344   return true;
345 }
346
347 bool CGUIControlFactory::GetTexture(const TiXmlNode* pRootNode, const char* strTag, CTextureInfo &image)
348 {
349   const TiXmlElement* pNode = pRootNode->FirstChildElement(strTag);
350   if (!pNode) return false;
351   const char *border = pNode->Attribute("border");
352   if (border)
353     GetRectFromString(border, image.border);
354   image.orientation = 0;
355   const char *flipX = pNode->Attribute("flipx");
356   if (flipX && strcmpi(flipX, "true") == 0) image.orientation = 1;
357   const char *flipY = pNode->Attribute("flipy");
358   if (flipY && strcmpi(flipY, "true") == 0) image.orientation = 3 - image.orientation;  // either 3 or 2
359   image.diffuse = pNode->Attribute("diffuse");
360   image.diffuseColor.Parse(pNode->Attribute("colordiffuse"), 0);
361   const char *background = pNode->Attribute("background");
362   if (background && strnicmp(background, "true", 4) == 0)
363     image.useLarge = true;
364   image.filename = (pNode->FirstChild() && pNode->FirstChild()->ValueStr() != "-") ? pNode->FirstChild()->Value() : "";
365   return true;
366 }
367
368 void CGUIControlFactory::GetRectFromString(const CStdString &string, CRect &rect)
369 {
370   // format is rect="left[,top,right,bottom]"
371   CStdStringArray strRect;
372   StringUtils::SplitString(string, ",", strRect);
373   if (strRect.size() == 1)
374   {
375     rect.x1 = (float)atof(strRect[0].c_str());
376     rect.y1 = rect.x1;
377     rect.x2 = rect.x1;
378     rect.y2 = rect.x1;
379   }
380   else if (strRect.size() == 4)
381   {
382     rect.x1 = (float)atof(strRect[0].c_str());
383     rect.y1 = (float)atof(strRect[1].c_str());
384     rect.x2 = (float)atof(strRect[2].c_str());
385     rect.y2 = (float)atof(strRect[3].c_str());
386   }
387 }
388
389 bool CGUIControlFactory::GetAlignment(const TiXmlNode* pRootNode, const char* strTag, uint32_t& alignment)
390 {
391   const TiXmlNode* pNode = pRootNode->FirstChild(strTag);
392   if (!pNode || !pNode->FirstChild()) return false;
393
394   CStdString strAlign = pNode->FirstChild()->Value();
395   if (strAlign == "right" || strAlign == "bottom") alignment = XBFONT_RIGHT;
396   else if (strAlign == "center") alignment = XBFONT_CENTER_X;
397   else if (strAlign == "justify") alignment = XBFONT_JUSTIFIED;
398   else alignment = XBFONT_LEFT;
399   return true;
400 }
401
402 bool CGUIControlFactory::GetAlignmentY(const TiXmlNode* pRootNode, const char* strTag, uint32_t& alignment)
403 {
404   const TiXmlNode* pNode = pRootNode->FirstChild(strTag );
405   if (!pNode || !pNode->FirstChild())
406   {
407     return false;
408   }
409
410   CStdString strAlign = pNode->FirstChild()->Value();
411
412   alignment = 0;
413   if (strAlign == "center")
414   {
415     alignment = XBFONT_CENTER_Y;
416   }
417
418   return true;
419 }
420
421 bool CGUIControlFactory::GetConditionalVisibility(const TiXmlNode* control, CStdString &condition, CStdString &allowHiddenFocus)
422 {
423   const TiXmlElement* node = control->FirstChildElement("visible");
424   if (!node) return false;
425   vector<CStdString> conditions;
426   while (node)
427   {
428     const char *hidden = node->Attribute("allowhiddenfocus");
429     if (hidden)
430       allowHiddenFocus = hidden;
431     // add to our condition string
432     if (!node->NoChildren())
433       conditions.push_back(node->FirstChild()->Value());
434     node = node->NextSiblingElement("visible");
435   }
436   if (!conditions.size())
437     return false;
438   if (conditions.size() == 1)
439     condition = conditions[0];
440   else
441   { // multiple conditions should be anded together
442     condition = "[";
443     for (unsigned int i = 0; i < conditions.size() - 1; i++)
444       condition += conditions[i] + "] + [";
445     condition += conditions[conditions.size() - 1] + "]";
446   }
447   return true;
448 }
449
450 bool CGUIControlFactory::GetConditionalVisibility(const TiXmlNode *control, CStdString &condition)
451 {
452   CStdString allowHiddenFocus;
453   return GetConditionalVisibility(control, condition, allowHiddenFocus);
454 }
455
456 bool CGUIControlFactory::GetAnimations(TiXmlNode *control, const CRect &rect, int context, vector<CAnimation> &animations)
457 {
458   TiXmlElement* node = control->FirstChildElement("animation");
459   bool ret = false;
460   if (node)
461     animations.clear();
462   while (node)
463   {
464     ret = true;
465     if (node->FirstChild())
466     {
467       CAnimation anim;
468       anim.Create(node, rect, context);
469       animations.push_back(anim);
470       if (strcmpi(node->FirstChild()->Value(), "VisibleChange") == 0)
471       { // add the hidden one as well
472         TiXmlElement hidden(*node);
473         hidden.FirstChild()->SetValue("hidden");
474         const char *start = hidden.Attribute("start");
475         const char *end = hidden.Attribute("end");
476         if (start && end)
477         {
478           CStdString temp = end;
479           hidden.SetAttribute("end", start);
480           hidden.SetAttribute("start", temp.c_str());
481         }
482         else if (start)
483           hidden.SetAttribute("end", start);
484         else if (end)
485           hidden.SetAttribute("start", end);
486         CAnimation anim2;
487         anim2.Create(&hidden, rect, context);
488         animations.push_back(anim2);
489       }
490     }
491     node = node->NextSiblingElement("animation");
492   }
493   return ret;
494 }
495
496 bool CGUIControlFactory::GetActions(const TiXmlNode* pRootNode, const char* strTag, CGUIAction& action)
497 {
498   action.m_actions.clear();
499   const TiXmlElement* pElement = pRootNode->FirstChildElement(strTag);
500   while (pElement)
501   {
502     if (pElement->FirstChild())
503     {
504       CGUIAction::cond_action_pair pair;
505       pair.condition = pElement->Attribute("condition");
506       pair.action = pElement->FirstChild()->Value();
507       action.m_actions.push_back(pair);
508     }
509     pElement = pElement->NextSiblingElement(strTag);
510   }
511   return action.m_actions.size() > 0;
512 }
513
514 bool CGUIControlFactory::GetHitRect(const TiXmlNode *control, CRect &rect)
515 {
516   const TiXmlElement* node = control->FirstChildElement("hitrect");
517   if (node)
518   {
519     node->QueryFloatAttribute("x", &rect.x1);
520     node->QueryFloatAttribute("y", &rect.y1);
521     if (node->Attribute("w"))
522       rect.x2 = (float)atof(node->Attribute("w")) + rect.x1;
523     if (node->Attribute("h"))
524       rect.y2 = (float)atof(node->Attribute("h")) + rect.y1;
525     return true;
526   }
527   return false;
528 }
529
530 bool CGUIControlFactory::GetScroller(const TiXmlNode *control, const CStdString &scrollerTag, CScroller& scroller)
531 {
532   const TiXmlElement* node = control->FirstChildElement(scrollerTag);
533   if (node)
534   {
535     unsigned int scrollTime;
536     if (XMLUtils::GetUInt(control, scrollerTag, scrollTime))
537     {
538       scroller = CScroller(scrollTime, CAnimEffect::GetTweener(node));
539       return true;
540     }
541   }
542   return false;
543 }
544
545 bool CGUIControlFactory::GetColor(const TiXmlNode *control, const char *strTag, color_t &value)
546 {
547   const TiXmlElement* node = control->FirstChildElement(strTag);
548   if (node && node->FirstChild())
549   {
550     value = g_colorManager.GetColor(node->FirstChild()->Value());
551     return true;
552   }
553   return false;
554 }
555
556 bool CGUIControlFactory::GetInfoColor(const TiXmlNode *control, const char *strTag, CGUIInfoColor &value,int parentID)
557 {
558   const TiXmlElement* node = control->FirstChildElement(strTag);
559   if (node && node->FirstChild())
560   {
561     value.Parse(node->FirstChild()->Value(), parentID);
562     return true;
563   }
564   return false;
565 }
566
567 void CGUIControlFactory::GetInfoLabel(const TiXmlNode *pControlNode, const CStdString &labelTag, CGUIInfoLabel &infoLabel, int parentID)
568 {
569   vector<CGUIInfoLabel> labels;
570   GetInfoLabels(pControlNode, labelTag, labels, parentID);
571   if (labels.size())
572     infoLabel = labels[0];
573 }
574
575 bool CGUIControlFactory::GetInfoLabelFromElement(const TiXmlElement *element, CGUIInfoLabel &infoLabel, int parentID)
576 {
577   if (!element || !element->FirstChild())
578     return false;
579
580   CStdString label = element->FirstChild()->Value();
581   if (label.empty() || label == "-")
582     return false;
583
584   CStdString fallback = element->Attribute("fallback");
585   if (StringUtils::IsNaturalNumber(label))
586     label = g_localizeStrings.Get(atoi(label));
587   if (StringUtils::IsNaturalNumber(fallback))
588     fallback = g_localizeStrings.Get(atoi(fallback));
589   else
590     g_charsetConverter.unknownToUTF8(fallback);
591   infoLabel.SetLabel(label, fallback, parentID);
592   return true;
593 }
594
595 void CGUIControlFactory::GetInfoLabels(const TiXmlNode *pControlNode, const CStdString &labelTag, vector<CGUIInfoLabel> &infoLabels, int parentID)
596 {
597   // we can have the following infolabels:
598   // 1.  <number>1234</number> -> direct number
599   // 2.  <label>number</label> -> lookup in localizestrings
600   // 3.  <label fallback="blah">$LOCALIZE(blah) $INFO(blah)</label> -> infolabel with given fallback
601   // 4.  <info>ListItem.Album</info> (uses <label> as fallback)
602   int labelNumber = 0;
603   if (XMLUtils::GetInt(pControlNode, "number", labelNumber))
604   {
605     CStdString label = StringUtils::Format("%i", labelNumber);
606     infoLabels.push_back(CGUIInfoLabel(label));
607     return; // done
608   }
609   const TiXmlElement *labelNode = pControlNode->FirstChildElement(labelTag);
610   while (labelNode)
611   {
612     CGUIInfoLabel label;
613     if (GetInfoLabelFromElement(labelNode, label, parentID))
614       infoLabels.push_back(label);
615     labelNode = labelNode->NextSiblingElement(labelTag);
616   }
617   const TiXmlNode *infoNode = pControlNode->FirstChild("info");
618   if (infoNode)
619   { // <info> nodes override <label>'s (backward compatibility)
620     CStdString fallback;
621     if (infoLabels.size())
622       fallback = infoLabels[0].GetLabel(0);
623     infoLabels.clear();
624     while (infoNode)
625     {
626       if (infoNode->FirstChild())
627       {
628         CStdString info = StringUtils::Format("$INFO[%s]", infoNode->FirstChild()->Value());
629         infoLabels.push_back(CGUIInfoLabel(info, fallback, parentID));
630       }
631       infoNode = infoNode->NextSibling("info");
632     }
633   }
634 }
635
636 // Convert a string to a GUI label, by translating/parsing the label for localisable strings
637 CStdString CGUIControlFactory::FilterLabel(const CStdString &label)
638 {
639   CStdString viewLabel = label;
640   if (StringUtils::IsNaturalNumber(viewLabel))
641     viewLabel = g_localizeStrings.Get(atoi(label));
642   else
643     g_charsetConverter.unknownToUTF8(viewLabel);
644   return viewLabel;
645 }
646
647 bool CGUIControlFactory::GetString(const TiXmlNode* pRootNode, const char *strTag, CStdString &text)
648 {
649   if (!XMLUtils::GetString(pRootNode, strTag, text))
650     return false;
651   if (text == "-")
652     text.clear();
653   if (StringUtils::IsNaturalNumber(text))
654     text = g_localizeStrings.Get(atoi(text.c_str()));
655   return true;
656 }
657
658 CStdString CGUIControlFactory::GetType(const TiXmlElement *pControlNode)
659 {
660   CStdString type;
661   const char *szType = pControlNode->Attribute("type");
662   if (szType)
663     type = szType;
664   else  // backward compatibility - not desired
665     XMLUtils::GetString(pControlNode, "type", type);
666   return type;
667 }
668
669 CGUIControl* CGUIControlFactory::Create(int parentID, const CRect &rect, TiXmlElement* pControlNode, bool insideContainer)
670 {
671   // get the control type
672   CStdString strType = GetType(pControlNode);
673   CGUIControl::GUICONTROLTYPES type = TranslateControlType(strType);
674
675   int id = 0;
676   float posX = 0, posY = 0;
677   float width = 0, height = 0;
678   float minHeight = 0, minWidth = 0;
679
680   CGUIAction leftActions, rightActions, upActions, downActions, backActions, nextActions, prevActions;
681
682   int pageControl = 0;
683   CGUIInfoColor colorDiffuse(0xFFFFFFFF);
684   int defaultControl = 0;
685   bool  defaultAlways = false;
686   CStdString strTmp;
687   int singleInfo = 0;
688   CStdString strLabel;
689   int iUrlSet=0;
690   CStdString toggleSelect;
691
692   float spinWidth = 16;
693   float spinHeight = 16;
694   float spinPosX = 0, spinPosY = 0;
695   float checkWidth = 0, checkHeight = 0;
696   CStdString strSubType;
697   int iType = SPIN_CONTROL_TYPE_TEXT;
698   int iMin = 0;
699   int iMax = 100;
700   int iInterval = 1;
701   float fMin = 0.0f;
702   float fMax = 1.0f;
703   float fInterval = 0.1f;
704   bool bReverse = true;
705   bool bReveal = false;
706   CTextureInfo textureBackground, textureLeft, textureRight, textureMid, textureOverlay;
707   CTextureInfo textureNib, textureNibFocus, textureBar, textureBarFocus;
708   CTextureInfo textureLeftFocus, textureRightFocus;
709   CTextureInfo textureUp, textureDown;
710   CTextureInfo textureUpFocus, textureDownFocus;
711   CTextureInfo texture, borderTexture;
712   CGUIInfoLabel textureFile;
713   CTextureInfo textureCheckMark, textureCheckMarkNF;
714   CTextureInfo textureFocus, textureNoFocus;
715   CTextureInfo textureAltFocus, textureAltNoFocus;
716   CTextureInfo textureRadioOnFocus, textureRadioOnNoFocus;
717   CTextureInfo textureRadioOffFocus, textureRadioOffNoFocus;
718   CTextureInfo imageNoFocus, imageFocus;
719   CTextureInfo textureProgressIndicator;
720   CGUIInfoLabel texturePath;
721   CRect borderSize;
722
723   float sliderWidth = 150, sliderHeight = 16;
724   CPoint offset;
725
726   bool bHasPath = false;
727   CGUIAction clickActions;
728   CGUIAction altclickActions;
729   CGUIAction focusActions;
730   CGUIAction unfocusActions;
731   CGUIAction textChangeActions;
732   CStdString strTitle = "";
733   CStdString strRSSTags = "";
734
735   float buttonGap = 5;
736   int iMovementRange = 0;
737   CAspectRatio aspect;
738 #ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY
739   if (insideContainer)  // default for inside containers is keep
740     aspect.ratio = CAspectRatio::AR_KEEP;
741 #endif
742
743   CStdString allowHiddenFocus;
744   CStdString enableCondition;
745
746   vector<CAnimation> animations;
747
748   bool bScrollLabel = false;
749   bool bPulse = true;
750   unsigned int timePerImage = 0;
751   unsigned int fadeTime = 0;
752   unsigned int timeToPauseAtEnd = 0;
753   bool randomized = false;
754   bool loop = true;
755   bool wrapMultiLine = false;
756   ORIENTATION orientation = VERTICAL;
757   bool showOnePage = true;
758   bool scrollOut = true;
759   int preloadItems = 0;
760
761   CLabelInfo labelInfo;
762   CLabelInfo spinInfo;
763
764   CGUIInfoColor textColor3;
765   CGUIInfoColor headlineColor;
766
767   float radioWidth = 0;
768   float radioHeight = 0;
769   float radioPosX = 0;
770   float radioPosY = 0;
771
772   CStdString altLabel;
773   CStdString strLabel2;
774   CStdString action;
775
776   int focusPosition = 0;
777   int scrollTime = 200;
778   int timeBlocks = 36;
779   int rulerUnit = 12;
780   bool useControlCoords = false;
781   bool renderFocusedLast = false;
782
783   CRect hitRect;
784   CPoint camera;
785   bool   hasCamera = false;
786   bool resetOnLabelChange = true;
787   bool bPassword = false;
788   CStdString visibleCondition;
789
790   /////////////////////////////////////////////////////////////////////////////
791   // Read control properties from XML
792   //
793
794   if (!pControlNode->Attribute("id", (int*) &id))
795     XMLUtils::GetInt(pControlNode, "id", (int&) id);       // backward compatibility - not desired
796   // TODO: Perhaps we should check here whether id is valid for focusable controls
797   // such as buttons etc.  For labels/fadelabels/images it does not matter
798
799   GetAlignment(pControlNode, "align", labelInfo.align);
800   if (!GetDimensions(pControlNode, "left", "right", "centerleft", "centerright", "width", rect.Width(), posX, width, minWidth))
801   { // didn't get 2 dimensions, so test for old <posx> as well
802     if (GetPosition(pControlNode, "posx", rect.Width(), posX))
803     { // <posx> available, so use it along with any hacks we used to support
804       if (!insideContainer &&
805           type == CGUIControl::GUICONTROL_LABEL &&
806           (labelInfo.align & XBFONT_RIGHT))
807         posX -= width;
808     }
809     if (!width)
810       width = max(rect.Width() - posX, 0.0f);
811   }
812   if (!GetDimensions(pControlNode, "top", "bottom", "centertop", "centerbottom", "height", rect.Height(), posY, height, minHeight))
813   {
814     GetPosition(pControlNode, "posy", rect.Height(), posY);
815     if (!height)
816       height = max(rect.Height() - posY, 0.0f);
817   }
818
819   XMLUtils::GetFloat(pControlNode, "offsetx", offset.x);
820   XMLUtils::GetFloat(pControlNode, "offsety", offset.y);
821
822   hitRect.SetRect(posX, posY, posX + width, posY + height);
823   GetHitRect(pControlNode, hitRect);
824
825   GetActions(pControlNode, "onup",    upActions);
826   GetActions(pControlNode, "ondown",  downActions);
827   GetActions(pControlNode, "onleft",  leftActions);
828   GetActions(pControlNode, "onright", rightActions);
829   GetActions(pControlNode, "onnext",  nextActions);
830   GetActions(pControlNode, "onprev",  prevActions);
831   GetActions(pControlNode, "onback",  backActions);
832
833   if (XMLUtils::GetInt(pControlNode, "defaultcontrol", defaultControl))
834   {
835     const char *always = pControlNode->FirstChildElement("defaultcontrol")->Attribute("always");
836     if (always && strnicmp(always, "true", 4) == 0)
837       defaultAlways = true;
838   }
839   XMLUtils::GetInt(pControlNode, "pagecontrol", pageControl);
840
841   GetInfoColor(pControlNode, "colordiffuse", colorDiffuse, parentID);
842
843   GetConditionalVisibility(pControlNode, visibleCondition, allowHiddenFocus);
844   XMLUtils::GetString(pControlNode, "enable", enableCondition);
845
846   CRect animRect(posX, posY, posX + width, posY + height);
847   GetAnimations(pControlNode, animRect, parentID, animations);
848
849   GetInfoColor(pControlNode, "textcolor", labelInfo.textColor, parentID);
850   GetInfoColor(pControlNode, "focusedcolor", labelInfo.focusedColor, parentID);
851   GetInfoColor(pControlNode, "disabledcolor", labelInfo.disabledColor, parentID);
852   GetInfoColor(pControlNode, "shadowcolor", labelInfo.shadowColor, parentID);
853   GetInfoColor(pControlNode, "selectedcolor", labelInfo.selectedColor, parentID);
854   GetInfoColor(pControlNode, "invalidcolor", labelInfo.invalidColor, parentID);
855   XMLUtils::GetFloat(pControlNode, "textoffsetx", labelInfo.offsetX);
856   XMLUtils::GetFloat(pControlNode, "textoffsety", labelInfo.offsetY);
857   int angle = 0;  // use the negative angle to compensate for our vertically flipped cartesian plane
858   if (XMLUtils::GetInt(pControlNode, "angle", angle)) labelInfo.angle = (float)-angle;
859   CStdString strFont;
860   if (XMLUtils::GetString(pControlNode, "font", strFont))
861     labelInfo.font = g_fontManager.GetFont(strFont);
862   uint32_t alignY = 0;
863   if (GetAlignmentY(pControlNode, "aligny", alignY))
864     labelInfo.align |= alignY;
865   if (XMLUtils::GetFloat(pControlNode, "textwidth", labelInfo.width))
866     labelInfo.align |= XBFONT_TRUNCATED;
867
868   GetActions(pControlNode, "onclick", clickActions);
869   GetActions(pControlNode, "ontextchange", textChangeActions);
870   GetActions(pControlNode, "onfocus", focusActions);
871   GetActions(pControlNode, "onunfocus", unfocusActions);
872   focusActions.m_sendThreadMessages = unfocusActions.m_sendThreadMessages = true;
873   GetActions(pControlNode, "altclick", altclickActions);
874
875   CStdString infoString;
876   if (XMLUtils::GetString(pControlNode, "info", infoString))
877     singleInfo = g_infoManager.TranslateString(infoString);
878
879   GetTexture(pControlNode, "texturefocus", textureFocus);
880   GetTexture(pControlNode, "texturenofocus", textureNoFocus);
881   GetTexture(pControlNode, "alttexturefocus", textureAltFocus);
882   GetTexture(pControlNode, "alttexturenofocus", textureAltNoFocus);
883
884   XMLUtils::GetString(pControlNode, "usealttexture", toggleSelect);
885   XMLUtils::GetString(pControlNode, "selected", toggleSelect);
886
887   XMLUtils::GetBoolean(pControlNode, "haspath", bHasPath);
888
889   GetTexture(pControlNode, "textureup", textureUp);
890   GetTexture(pControlNode, "texturedown", textureDown);
891   GetTexture(pControlNode, "textureupfocus", textureUpFocus);
892   GetTexture(pControlNode, "texturedownfocus", textureDownFocus);
893
894   GetTexture(pControlNode, "textureleft", textureLeft);
895   GetTexture(pControlNode, "textureright", textureRight);
896   GetTexture(pControlNode, "textureleftfocus", textureLeftFocus);
897   GetTexture(pControlNode, "texturerightfocus", textureRightFocus);
898
899   GetInfoColor(pControlNode, "spincolor", spinInfo.textColor, parentID);
900   if (XMLUtils::GetString(pControlNode, "spinfont", strFont))
901     spinInfo.font = g_fontManager.GetFont(strFont);
902   if (!spinInfo.font) spinInfo.font = labelInfo.font;
903
904   XMLUtils::GetFloat(pControlNode, "spinwidth", spinWidth);
905   XMLUtils::GetFloat(pControlNode, "spinheight", spinHeight);
906   XMLUtils::GetFloat(pControlNode, "spinposx", spinPosX);
907   XMLUtils::GetFloat(pControlNode, "spinposy", spinPosY);
908
909   XMLUtils::GetFloat(pControlNode, "markwidth", checkWidth);
910   XMLUtils::GetFloat(pControlNode, "markheight", checkHeight);
911   XMLUtils::GetFloat(pControlNode, "sliderwidth", sliderWidth);
912   XMLUtils::GetFloat(pControlNode, "sliderheight", sliderHeight);
913   GetTexture(pControlNode, "texturecheckmark", textureCheckMark);
914   GetTexture(pControlNode, "texturecheckmarknofocus", textureCheckMarkNF);
915   if (!GetTexture(pControlNode, "textureradioonfocus", textureRadioOnFocus) || !GetTexture(pControlNode, "textureradioonnofocus", textureRadioOnNoFocus))
916   {
917     GetTexture(pControlNode, "textureradiofocus", textureRadioOnFocus);    // backward compatibility
918     GetTexture(pControlNode, "textureradioon", textureRadioOnFocus);
919     textureRadioOnNoFocus = textureRadioOnFocus;
920   }
921   if (!GetTexture(pControlNode, "textureradioofffocus", textureRadioOffFocus) || !GetTexture(pControlNode, "textureradiooffnofocus", textureRadioOffNoFocus))
922   {
923     GetTexture(pControlNode, "textureradionofocus", textureRadioOffFocus);    // backward compatibility
924     GetTexture(pControlNode, "textureradiooff", textureRadioOffFocus);
925     textureRadioOffNoFocus = textureRadioOffFocus;
926   }
927
928   GetTexture(pControlNode, "texturesliderbackground", textureBackground);
929   GetTexture(pControlNode, "texturesliderbar", textureBar);
930   GetTexture(pControlNode, "texturesliderbarfocus", textureBarFocus);
931   GetTexture(pControlNode, "textureslidernib", textureNib);
932   GetTexture(pControlNode, "textureslidernibfocus", textureNibFocus);
933
934   XMLUtils::GetString(pControlNode, "title", strTitle);
935   XMLUtils::GetString(pControlNode, "tagset", strRSSTags);
936   GetInfoColor(pControlNode, "headlinecolor", headlineColor, parentID);
937   GetInfoColor(pControlNode, "titlecolor", textColor3, parentID);
938
939   if (XMLUtils::GetString(pControlNode, "subtype", strSubType))
940   {
941     StringUtils::ToLower(strSubType);
942
943     if ( strSubType == "int")
944       iType = SPIN_CONTROL_TYPE_INT;
945     else if ( strSubType == "page")
946       iType = SPIN_CONTROL_TYPE_PAGE;
947     else if ( strSubType == "float")
948       iType = SPIN_CONTROL_TYPE_FLOAT;
949     else
950       iType = SPIN_CONTROL_TYPE_TEXT;
951   }
952
953   if (!GetIntRange(pControlNode, "range", iMin, iMax, iInterval))
954   {
955     GetFloatRange(pControlNode, "range", fMin, fMax, fInterval);
956   }
957
958   XMLUtils::GetBoolean(pControlNode, "reverse", bReverse);
959   XMLUtils::GetBoolean(pControlNode, "reveal", bReveal);
960
961   GetTexture(pControlNode, "texturebg", textureBackground);
962   GetTexture(pControlNode, "lefttexture", textureLeft);
963   GetTexture(pControlNode, "midtexture", textureMid);
964   GetTexture(pControlNode, "righttexture", textureRight);
965   GetTexture(pControlNode, "overlaytexture", textureOverlay);
966
967   // the <texture> tag can be overridden by the <info> tag
968   GetInfoTexture(pControlNode, "texture", texture, textureFile, parentID);
969 #ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY
970   if (type == CGUIControl::GUICONTROL_IMAGE && insideContainer && textureFile.IsConstant())
971     aspect.ratio = CAspectRatio::AR_STRETCH;
972 #endif
973
974   GetTexture(pControlNode, "bordertexture", borderTexture);
975
976   GetTexture(pControlNode, "imagefolder", imageNoFocus);
977   GetTexture(pControlNode, "imagefolderfocus", imageFocus);
978
979   // fade label can have a whole bunch, but most just have one
980   vector<CGUIInfoLabel> infoLabels;
981   GetInfoLabels(pControlNode, "label", infoLabels, parentID);
982
983   GetString(pControlNode, "label", strLabel);
984   GetString(pControlNode, "altlabel", altLabel);
985   GetString(pControlNode, "label2", strLabel2);
986
987   XMLUtils::GetBoolean(pControlNode, "wrapmultiline", wrapMultiLine);
988   XMLUtils::GetInt(pControlNode,"urlset",iUrlSet);
989
990   if ( XMLUtils::GetString(pControlNode, "orientation", strTmp) )
991   {
992     StringUtils::ToLower(strTmp);
993     if (strTmp == "horizontal")
994       orientation = HORIZONTAL;
995   }
996   XMLUtils::GetFloat(pControlNode, "itemgap", buttonGap);
997   XMLUtils::GetInt(pControlNode, "movement", iMovementRange);
998   GetAspectRatio(pControlNode, "aspectratio", aspect);
999   XMLUtils::GetBoolean(pControlNode, "scroll", bScrollLabel);
1000   XMLUtils::GetBoolean(pControlNode,"pulseonselect", bPulse);
1001   XMLUtils::GetInt(pControlNode, "timeblocks", timeBlocks);
1002   XMLUtils::GetInt(pControlNode, "rulerunit", rulerUnit);
1003   GetTexture(pControlNode, "progresstexture", textureProgressIndicator);
1004
1005   GetInfoTexture(pControlNode, "imagepath", texture, texturePath, parentID);
1006
1007   XMLUtils::GetUInt(pControlNode,"timeperimage", timePerImage);
1008   XMLUtils::GetUInt(pControlNode,"fadetime", fadeTime);
1009   XMLUtils::GetUInt(pControlNode,"pauseatend", timeToPauseAtEnd);
1010   XMLUtils::GetBoolean(pControlNode, "randomize", randomized);
1011   XMLUtils::GetBoolean(pControlNode, "loop", loop);
1012   XMLUtils::GetBoolean(pControlNode, "scrollout", scrollOut);
1013
1014   XMLUtils::GetFloat(pControlNode, "radiowidth", radioWidth);
1015   XMLUtils::GetFloat(pControlNode, "radioheight", radioHeight);
1016   XMLUtils::GetFloat(pControlNode, "radioposx", radioPosX);
1017   XMLUtils::GetFloat(pControlNode, "radioposy", radioPosY);
1018   CStdString borderStr;
1019   if (XMLUtils::GetString(pControlNode, "bordersize", borderStr))
1020     GetRectFromString(borderStr, borderSize);
1021
1022   XMLUtils::GetBoolean(pControlNode, "showonepage", showOnePage);
1023   XMLUtils::GetInt(pControlNode, "focusposition", focusPosition);
1024   XMLUtils::GetInt(pControlNode, "scrolltime", scrollTime);
1025   XMLUtils::GetInt(pControlNode, "preloaditems", preloadItems, 0, 2);
1026
1027   XMLUtils::GetBoolean(pControlNode, "usecontrolcoords", useControlCoords);
1028   XMLUtils::GetBoolean(pControlNode, "renderfocusedlast", renderFocusedLast);
1029   XMLUtils::GetBoolean(pControlNode, "resetonlabelchange", resetOnLabelChange);
1030
1031   XMLUtils::GetBoolean(pControlNode, "password", bPassword);
1032
1033   // view type
1034   VIEW_TYPE viewType = VIEW_TYPE_NONE;
1035   CStdString viewLabel;
1036   if (type == CGUIControl::GUICONTAINER_PANEL)
1037   {
1038     viewType = VIEW_TYPE_ICON;
1039     viewLabel = g_localizeStrings.Get(536);
1040   }
1041   else if (type == CGUIControl::GUICONTAINER_LIST)
1042   {
1043     viewType = VIEW_TYPE_LIST;
1044     viewLabel = g_localizeStrings.Get(535);
1045   }
1046   else
1047   {
1048     viewType = VIEW_TYPE_WRAP;
1049     viewLabel = g_localizeStrings.Get(541);
1050   }
1051   TiXmlElement *itemElement = pControlNode->FirstChildElement("viewtype");
1052   if (itemElement && itemElement->FirstChild())
1053   {
1054     CStdString type = itemElement->FirstChild()->Value();
1055     if (type == "list")
1056       viewType = VIEW_TYPE_LIST;
1057     else if (type == "icon")
1058       viewType = VIEW_TYPE_ICON;
1059     else if (type == "biglist")
1060       viewType = VIEW_TYPE_BIG_LIST;
1061     else if (type == "bigicon")
1062       viewType = VIEW_TYPE_BIG_ICON;
1063     else if (type == "wide")
1064       viewType = VIEW_TYPE_WIDE;
1065     else if (type == "bigwide")
1066       viewType = VIEW_TYPE_BIG_WIDE;
1067     else if (type == "wrap")
1068       viewType = VIEW_TYPE_WRAP;
1069     else if (type == "bigwrap")
1070       viewType = VIEW_TYPE_BIG_WRAP;
1071     else if (type == "info")
1072       viewType = VIEW_TYPE_INFO;
1073     else if (type == "biginfo")
1074       viewType = VIEW_TYPE_BIG_INFO;
1075     const char *label = itemElement->Attribute("label");
1076     if (label)
1077       viewLabel = CGUIInfoLabel::GetLabel(FilterLabel(label));
1078   }
1079
1080   TiXmlElement *cam = pControlNode->FirstChildElement("camera");
1081   if (cam)
1082   {
1083     hasCamera = true;
1084     cam->QueryFloatAttribute("x", &camera.x);
1085     cam->QueryFloatAttribute("y", &camera.y);
1086   }
1087
1088   XMLUtils::GetInt(pControlNode, "scrollspeed", labelInfo.scrollSpeed);
1089   spinInfo.scrollSpeed = labelInfo.scrollSpeed;
1090
1091   GetString(pControlNode, "scrollsuffix", labelInfo.scrollSuffix);
1092   spinInfo.scrollSuffix = labelInfo.scrollSuffix;
1093
1094   XMLUtils::GetString(pControlNode, "action", action);
1095
1096   /////////////////////////////////////////////////////////////////////////////
1097   // Instantiate a new control using the properties gathered above
1098   //
1099
1100   CGUIControl *control = NULL;
1101   if (type == CGUIControl::GUICONTROL_GROUP)
1102   {
1103     if (insideContainer)
1104     {
1105       control = new CGUIListGroup(parentID, id, posX, posY, width, height);
1106     }
1107     else
1108     {
1109       control = new CGUIControlGroup(
1110         parentID, id, posX, posY, width, height);
1111       ((CGUIControlGroup *)control)->SetDefaultControl(defaultControl, defaultAlways);
1112       ((CGUIControlGroup *)control)->SetRenderFocusedLast(renderFocusedLast);
1113     }
1114   }
1115   else if (type == CGUIControl::GUICONTROL_GROUPLIST)
1116   {
1117     CScroller scroller;
1118     GetScroller(pControlNode, "scrolltime", scroller);
1119
1120     control = new CGUIControlGroupList(
1121       parentID, id, posX, posY, width, height, buttonGap, pageControl, orientation, useControlCoords, labelInfo.align, scroller);
1122     ((CGUIControlGroup *)control)->SetRenderFocusedLast(renderFocusedLast);
1123     ((CGUIControlGroupList *)control)->SetMinSize(minWidth, minHeight);
1124   }
1125   else if (type == CGUIControl::GUICONTROL_LABEL)
1126   {
1127     const CGUIInfoLabel &content = (infoLabels.size()) ? infoLabels[0] : CGUIInfoLabel("");
1128     if (insideContainer)
1129     { // inside lists we use CGUIListLabel
1130       control = new CGUIListLabel(parentID, id, posX, posY, width, height, labelInfo, content, bScrollLabel);
1131     }
1132     else
1133     {
1134       control = new CGUILabelControl(
1135         parentID, id, posX, posY, width, height,
1136         labelInfo, wrapMultiLine, bHasPath);
1137       ((CGUILabelControl *)control)->SetInfo(content);
1138       ((CGUILabelControl *)control)->SetWidthControl(minWidth, bScrollLabel);
1139     }
1140   }
1141   else if (type == CGUIControl::GUICONTROL_EDIT)
1142   {
1143     control = new CGUIEditControl(
1144       parentID, id, posX, posY, width, height, textureFocus, textureNoFocus,
1145       labelInfo, strLabel);
1146
1147     CGUIInfoLabel hint_text;
1148     GetInfoLabel(pControlNode, "hinttext", hint_text, parentID);
1149     ((CGUIEditControl *) control)->SetHint(hint_text);
1150
1151     if (bPassword)
1152       ((CGUIEditControl *) control)->SetInputType(CGUIEditControl::INPUT_TYPE_PASSWORD, 0);
1153     ((CGUIEditControl *) control)->SetTextChangeActions(textChangeActions);
1154   }
1155   else if (type == CGUIControl::GUICONTROL_VIDEO)
1156   {
1157     control = new CGUIVideoControl(
1158       parentID, id, posX, posY, width, height);
1159   }
1160   else if (type == CGUIControl::GUICONTROL_FADELABEL)
1161   {
1162     control = new CGUIFadeLabelControl(
1163       parentID, id, posX, posY, width, height,
1164       labelInfo, scrollOut, timeToPauseAtEnd, resetOnLabelChange);
1165
1166     ((CGUIFadeLabelControl *)control)->SetInfo(infoLabels);
1167   }
1168   else if (type == CGUIControl::GUICONTROL_RSS)
1169   {
1170     control = new CGUIRSSControl(
1171       parentID, id, posX, posY, width, height,
1172       labelInfo, textColor3, headlineColor, strRSSTags);
1173     RssUrls::const_iterator iter = CRssManager::Get().GetUrls().find(iUrlSet);
1174     if (iter != CRssManager::Get().GetUrls().end())
1175       ((CGUIRSSControl *)control)->SetUrlSet(iUrlSet);
1176   }
1177   else if (type == CGUIControl::GUICONTROL_BUTTON)
1178   {
1179     control = new CGUIButtonControl(
1180       parentID, id, posX, posY, width, height,
1181       textureFocus, textureNoFocus,
1182       labelInfo);
1183
1184     ((CGUIButtonControl *)control)->SetLabel(strLabel);
1185     ((CGUIButtonControl *)control)->SetLabel2(strLabel2);
1186     ((CGUIButtonControl *)control)->SetClickActions(clickActions);
1187     ((CGUIButtonControl *)control)->SetFocusActions(focusActions);
1188     ((CGUIButtonControl *)control)->SetUnFocusActions(unfocusActions);
1189   }
1190   else if (type == CGUIControl::GUICONTROL_TOGGLEBUTTON)
1191   {
1192     control = new CGUIToggleButtonControl(
1193       parentID, id, posX, posY, width, height,
1194       textureFocus, textureNoFocus,
1195       textureAltFocus, textureAltNoFocus, labelInfo);
1196
1197     ((CGUIToggleButtonControl *)control)->SetLabel(strLabel);
1198     ((CGUIToggleButtonControl *)control)->SetAltLabel(altLabel);
1199     ((CGUIToggleButtonControl *)control)->SetClickActions(clickActions);
1200     ((CGUIToggleButtonControl *)control)->SetAltClickActions(altclickActions);
1201     ((CGUIToggleButtonControl *)control)->SetFocusActions(focusActions);
1202     ((CGUIToggleButtonControl *)control)->SetUnFocusActions(unfocusActions);
1203     ((CGUIToggleButtonControl *)control)->SetToggleSelect(toggleSelect);
1204   }
1205   else if (type == CGUIControl::GUICONTROL_CHECKMARK)
1206   {
1207     control = new CGUICheckMarkControl(
1208       parentID, id, posX, posY, width, height,
1209       textureCheckMark, textureCheckMarkNF,
1210       checkWidth, checkHeight, labelInfo);
1211
1212     ((CGUICheckMarkControl *)control)->SetLabel(strLabel);
1213   }
1214   else if (type == CGUIControl::GUICONTROL_RADIO)
1215   {
1216     control = new CGUIRadioButtonControl(
1217       parentID, id, posX, posY, width, height,
1218       textureFocus, textureNoFocus,
1219       labelInfo,
1220       textureRadioOnFocus, textureRadioOnNoFocus, textureRadioOffFocus, textureRadioOffNoFocus);
1221
1222     ((CGUIRadioButtonControl *)control)->SetLabel(strLabel);
1223     ((CGUIRadioButtonControl *)control)->SetRadioDimensions(radioPosX, radioPosY, radioWidth, radioHeight);
1224     ((CGUIRadioButtonControl *)control)->SetToggleSelect(toggleSelect);
1225     ((CGUIRadioButtonControl *)control)->SetClickActions(clickActions);
1226     ((CGUIRadioButtonControl *)control)->SetFocusActions(focusActions);
1227     ((CGUIRadioButtonControl *)control)->SetUnFocusActions(unfocusActions);
1228   }
1229   else if (type == CGUIControl::GUICONTROL_MULTISELECT)
1230   {
1231     CGUIInfoLabel label;
1232     if (infoLabels.size())
1233       label = infoLabels[0];
1234     control = new CGUIMultiSelectTextControl(
1235       parentID, id, posX, posY, width, height,
1236       textureFocus, textureNoFocus, labelInfo, label);
1237   }
1238   else if (type == CGUIControl::GUICONTROL_SPIN)
1239   {
1240     control = new CGUISpinControl(
1241       parentID, id, posX, posY, width, height,
1242       textureUp, textureDown, textureUpFocus, textureDownFocus,
1243       labelInfo, iType);
1244
1245     ((CGUISpinControl *)control)->SetReverse(bReverse);
1246
1247     if (iType == SPIN_CONTROL_TYPE_INT)
1248     {
1249       ((CGUISpinControl *)control)->SetRange(iMin, iMax);
1250     }
1251     else if (iType == SPIN_CONTROL_TYPE_PAGE)
1252     {
1253       ((CGUISpinControl *)control)->SetRange(iMin, iMax);
1254       ((CGUISpinControl *)control)->SetShowRange(true);
1255       ((CGUISpinControl *)control)->SetReverse(false);
1256       ((CGUISpinControl *)control)->SetShowOnePage(showOnePage);
1257     }
1258     else if (iType == SPIN_CONTROL_TYPE_FLOAT)
1259     {
1260       ((CGUISpinControl *)control)->SetFloatRange(fMin, fMax);
1261       ((CGUISpinControl *)control)->SetFloatInterval(fInterval);
1262     }
1263   }
1264   else if (type == CGUIControl::GUICONTROL_SLIDER)
1265   {
1266     control = new CGUISliderControl(
1267       parentID, id, posX, posY, width, height,
1268       textureBar, textureNib, textureNibFocus, SPIN_CONTROL_TYPE_TEXT);
1269
1270     ((CGUISliderControl *)control)->SetInfo(singleInfo);
1271     ((CGUISliderControl *)control)->SetAction(action);
1272   }
1273   else if (type == CGUIControl::GUICONTROL_SETTINGS_SLIDER)
1274   {
1275     control = new CGUISettingsSliderControl(
1276       parentID, id, posX, posY, width, height, sliderWidth, sliderHeight, textureFocus, textureNoFocus,
1277       textureBar, textureNib, textureNibFocus, labelInfo, SPIN_CONTROL_TYPE_TEXT);
1278
1279     ((CGUISettingsSliderControl *)control)->SetText(strLabel);
1280     ((CGUISettingsSliderControl *)control)->SetInfo(singleInfo);
1281   }
1282   else if (type == CGUIControl::GUICONTROL_SCROLLBAR)
1283   {
1284     control = new CGUIScrollBar(
1285       parentID, id, posX, posY, width, height,
1286       textureBackground, textureBar, textureBarFocus, textureNib, textureNibFocus, orientation, showOnePage);
1287   }
1288   else if (type == CGUIControl::GUICONTROL_PROGRESS)
1289   {
1290     control = new CGUIProgressControl(
1291       parentID, id, posX, posY, width, height,
1292       textureBackground, textureLeft, textureMid, textureRight,
1293       textureOverlay, bReveal);
1294
1295     ((CGUIProgressControl *)control)->SetInfo(singleInfo);
1296   }
1297   else if (type == CGUIControl::GUICONTROL_IMAGE)
1298   {
1299     if (strType == "largeimage")
1300       texture.useLarge = true;
1301
1302     // use a bordered texture if we have <bordersize> or <bordertexture> specified.
1303     if (borderTexture.filename.empty() && borderStr.empty())
1304       control = new CGUIImage(
1305         parentID, id, posX, posY, width, height, texture);
1306     else
1307       control = new CGUIBorderedImage(
1308         parentID, id, posX, posY, width, height, texture, borderTexture, borderSize);
1309     ((CGUIImage *)control)->SetInfo(textureFile);
1310     ((CGUIImage *)control)->SetAspectRatio(aspect);
1311     ((CGUIImage *)control)->SetCrossFade(fadeTime);
1312   }
1313   else if (type == CGUIControl::GUICONTROL_MULTI_IMAGE)
1314   {
1315     control = new CGUIMultiImage(
1316       parentID, id, posX, posY, width, height, texture, timePerImage, fadeTime, randomized, loop, timeToPauseAtEnd);
1317     ((CGUIMultiImage *)control)->SetInfo(texturePath);
1318     ((CGUIMultiImage *)control)->SetAspectRatio(aspect);
1319   }
1320   else if (type == CGUIControl::GUICONTAINER_LIST)
1321   {
1322     CScroller scroller;
1323     GetScroller(pControlNode, "scrolltime", scroller);
1324
1325     control = new CGUIListContainer(parentID, id, posX, posY, width, height, orientation, scroller, preloadItems);
1326     ((CGUIListContainer *)control)->LoadLayout(pControlNode);
1327     ((CGUIListContainer *)control)->LoadListProvider(pControlNode, defaultControl, defaultAlways);
1328     ((CGUIListContainer *)control)->SetType(viewType, viewLabel);
1329     ((CGUIListContainer *)control)->SetPageControl(pageControl);
1330     ((CGUIListContainer *)control)->SetRenderOffset(offset);
1331     ((CGUIListContainer *)control)->SetAutoScrolling(pControlNode);
1332   }
1333   else if (type == CGUIControl::GUICONTAINER_WRAPLIST)
1334   {
1335     CScroller scroller;
1336     GetScroller(pControlNode, "scrolltime", scroller);
1337
1338     control = new CGUIWrappingListContainer(parentID, id, posX, posY, width, height, orientation, scroller, preloadItems, focusPosition);
1339     ((CGUIWrappingListContainer *)control)->LoadLayout(pControlNode);
1340     ((CGUIWrappingListContainer *)control)->LoadListProvider(pControlNode, defaultControl, defaultAlways);
1341     ((CGUIWrappingListContainer *)control)->SetType(viewType, viewLabel);
1342     ((CGUIWrappingListContainer *)control)->SetPageControl(pageControl);
1343     ((CGUIWrappingListContainer *)control)->SetRenderOffset(offset);
1344     ((CGUIWrappingListContainer *)control)->SetAutoScrolling(pControlNode);
1345   }
1346   else if (type == CGUIControl::GUICONTAINER_EPGGRID)
1347   {
1348     control = new CGUIEPGGridContainer(parentID, id, posX, posY, width, height, orientation, scrollTime, preloadItems, timeBlocks, rulerUnit, textureProgressIndicator);
1349     ((CGUIEPGGridContainer *)control)->LoadLayout(pControlNode);
1350     ((CGUIEPGGridContainer *)control)->SetRenderOffset(offset);
1351     ((CGUIEPGGridContainer *)control)->SetType(viewType, viewLabel);
1352   }
1353   else if (type == CGUIControl::GUICONTAINER_FIXEDLIST)
1354   {
1355     CScroller scroller;
1356     GetScroller(pControlNode, "scrolltime", scroller);
1357
1358     control = new CGUIFixedListContainer(parentID, id, posX, posY, width, height, orientation, scroller, preloadItems, focusPosition, iMovementRange);
1359     ((CGUIFixedListContainer *)control)->LoadLayout(pControlNode);
1360     ((CGUIFixedListContainer *)control)->LoadListProvider(pControlNode, defaultControl, defaultAlways);
1361     ((CGUIFixedListContainer *)control)->SetType(viewType, viewLabel);
1362     ((CGUIFixedListContainer *)control)->SetPageControl(pageControl);
1363     ((CGUIFixedListContainer *)control)->SetRenderOffset(offset);
1364     ((CGUIFixedListContainer *)control)->SetAutoScrolling(pControlNode);
1365   }
1366   else if (type == CGUIControl::GUICONTAINER_PANEL)
1367   {
1368     CScroller scroller;
1369     GetScroller(pControlNode, "scrolltime", scroller); 
1370
1371     control = new CGUIPanelContainer(parentID, id, posX, posY, width, height, orientation, scroller, preloadItems);
1372     ((CGUIPanelContainer *)control)->LoadLayout(pControlNode);
1373     ((CGUIPanelContainer *)control)->LoadListProvider(pControlNode, defaultControl, defaultAlways);
1374     ((CGUIPanelContainer *)control)->SetType(viewType, viewLabel);
1375     ((CGUIPanelContainer *)control)->SetPageControl(pageControl);
1376     ((CGUIPanelContainer *)control)->SetRenderOffset(offset);
1377     ((CGUIPanelContainer *)control)->SetAutoScrolling(pControlNode);
1378   }
1379   else if (type == CGUIControl::GUICONTROL_TEXTBOX)
1380   {
1381     control = new CGUITextBox(
1382       parentID, id, posX, posY, width, height,
1383       labelInfo, scrollTime);
1384
1385     ((CGUITextBox *)control)->SetPageControl(pageControl);
1386     if (infoLabels.size())
1387       ((CGUITextBox *)control)->SetInfo(infoLabels[0]);
1388     ((CGUITextBox *)control)->SetAutoScrolling(pControlNode);
1389   }
1390   else if (type == CGUIControl::GUICONTROL_SELECTBUTTON)
1391   {
1392     control = new CGUISelectButtonControl(
1393       parentID, id, posX, posY,
1394       width, height, textureFocus, textureNoFocus,
1395       labelInfo,
1396       textureBackground, textureLeft, textureLeftFocus, textureRight, textureRightFocus);
1397
1398     ((CGUISelectButtonControl *)control)->SetLabel(strLabel);
1399   }
1400   else if (type == CGUIControl::GUICONTROL_MOVER)
1401   {
1402     control = new CGUIMoverControl(
1403       parentID, id, posX, posY, width, height,
1404       textureFocus, textureNoFocus);
1405   }
1406   else if (type == CGUIControl::GUICONTROL_RESIZE)
1407   {
1408     control = new CGUIResizeControl(
1409       parentID, id, posX, posY, width, height,
1410       textureFocus, textureNoFocus);
1411   }
1412   else if (type == CGUIControl::GUICONTROL_SPINEX)
1413   {
1414     control = new CGUISpinControlEx(
1415       parentID, id, posX, posY, width, height, spinWidth, spinHeight,
1416       labelInfo, textureFocus, textureNoFocus, textureUp, textureDown, textureUpFocus, textureDownFocus,
1417       labelInfo, iType);
1418
1419     ((CGUISpinControlEx *)control)->SetSpinPosition(spinPosX);
1420     ((CGUISpinControlEx *)control)->SetText(strLabel);
1421     ((CGUISpinControlEx *)control)->SetReverse(bReverse);
1422   }
1423   else if (type == CGUIControl::GUICONTROL_VISUALISATION)
1424   {
1425     control = new CGUIVisualisationControl(parentID, id, posX, posY, width, height);
1426   }
1427   else if (type == CGUIControl::GUICONTROL_RENDERADDON)
1428   {
1429     control = new CGUIRenderingControl(parentID, id, posX, posY, width, height);
1430   }
1431
1432   // things that apply to all controls
1433   if (control)
1434   {
1435     control->SetHitRect(hitRect);
1436     control->SetVisibleCondition(visibleCondition, allowHiddenFocus);
1437     control->SetEnableCondition(enableCondition);
1438     control->SetAnimations(animations);
1439     control->SetColorDiffuse(colorDiffuse);
1440     control->SetNavigationActions(upActions, downActions, leftActions, rightActions, backActions);
1441     control->SetPulseOnSelect(bPulse);
1442     if (hasCamera)
1443       control->SetCamera(camera);
1444   }
1445   return control;
1446 }