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