Merge pull request #26032 from sundermann/android-make-packaging
[xbmc.git] / xbmc / guilib / GUIControlFactory.cpp
bloba58622275e0edc3e35d45b33c264c61218f2276a
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "GUIControlFactory.h"
11 #include "GUIAction.h"
12 #include "GUIBorderedImage.h"
13 #include "GUIButtonControl.h"
14 #include "GUIColorButtonControl.h"
15 #include "GUIColorManager.h"
16 #include "GUIControlGroup.h"
17 #include "GUIControlGroupList.h"
18 #include "GUIEditControl.h"
19 #include "GUIFadeLabelControl.h"
20 #include "GUIFixedListContainer.h"
21 #include "GUIFontManager.h"
22 #include "GUIImage.h"
23 #include "GUIInfoManager.h"
24 #include "GUILabelControl.h"
25 #include "GUIListContainer.h"
26 #include "GUIListGroup.h"
27 #include "GUIListLabel.h"
28 #include "GUIMoverControl.h"
29 #include "GUIMultiImage.h"
30 #include "GUIPanelContainer.h"
31 #include "GUIProgressControl.h"
32 #include "GUIRSSControl.h"
33 #include "GUIRadioButtonControl.h"
34 #include "GUIRangesControl.h"
35 #include "GUIRenderingControl.h"
36 #include "GUIResizeControl.h"
37 #include "GUIScrollBarControl.h"
38 #include "GUISettingsSliderControl.h"
39 #include "GUISliderControl.h"
40 #include "GUISpinControl.h"
41 #include "GUISpinControlEx.h"
42 #include "GUITextBox.h"
43 #include "GUIToggleButtonControl.h"
44 #include "GUIVideoControl.h"
45 #include "GUIVisualisationControl.h"
46 #include "GUIWrappingListContainer.h"
47 #include "LocalizeStrings.h"
48 #include "addons/Skin.h"
49 #include "cores/RetroPlayer/guicontrols/GUIGameControl.h"
50 #include "games/controllers/guicontrols/GUIGameController.h"
51 #include "games/controllers/guicontrols/GUIGameControllerList.h"
52 #include "input/actions/ActionIDs.h"
53 #include "pvr/guilib/GUIEPGGridContainer.h"
54 #include "utils/CharsetConverter.h"
55 #include "utils/RssManager.h"
56 #include "utils/StringUtils.h"
57 #include "utils/XMLUtils.h"
58 #include "utils/log.h"
60 using namespace KODI;
61 using namespace KODI::GUILIB;
62 using namespace PVR;
64 typedef struct
66 const char* name;
67 CGUIControl::GUICONTROLTYPES type;
68 } ControlMapping;
70 static const ControlMapping controls[] = {
71 {"button", CGUIControl::GUICONTROL_BUTTON},
72 {"colorbutton", CGUIControl::GUICONTROL_COLORBUTTON},
73 {"edit", CGUIControl::GUICONTROL_EDIT},
74 {"epggrid", CGUIControl::GUICONTAINER_EPGGRID},
75 {"fadelabel", CGUIControl::GUICONTROL_FADELABEL},
76 {"fixedlist", CGUIControl::GUICONTAINER_FIXEDLIST},
77 {"gamecontroller", CGUIControl::GUICONTROL_GAMECONTROLLER},
78 {"gamecontrollerlist", CGUIControl::GUICONTROL_GAMECONTROLLERLIST},
79 {"gamewindow", CGUIControl::GUICONTROL_GAME},
80 {"group", CGUIControl::GUICONTROL_GROUP},
81 {"group", CGUIControl::GUICONTROL_LISTGROUP},
82 {"grouplist", CGUIControl::GUICONTROL_GROUPLIST},
83 {"image", CGUIControl::GUICONTROL_IMAGE},
84 {"image", CGUIControl::GUICONTROL_BORDEREDIMAGE},
85 {"label", CGUIControl::GUICONTROL_LABEL},
86 {"label", CGUIControl::GUICONTROL_LISTLABEL},
87 {"list", CGUIControl::GUICONTAINER_LIST},
88 {"mover", CGUIControl::GUICONTROL_MOVER},
89 {"multiimage", CGUIControl::GUICONTROL_MULTI_IMAGE},
90 {"panel", CGUIControl::GUICONTAINER_PANEL},
91 {"progress", CGUIControl::GUICONTROL_PROGRESS},
92 {"radiobutton", CGUIControl::GUICONTROL_RADIO},
93 {"ranges", CGUIControl::GUICONTROL_RANGES},
94 {"renderaddon", CGUIControl::GUICONTROL_RENDERADDON},
95 {"resize", CGUIControl::GUICONTROL_RESIZE},
96 {"rss", CGUIControl::GUICONTROL_RSS},
97 {"scrollbar", CGUIControl::GUICONTROL_SCROLLBAR},
98 {"slider", CGUIControl::GUICONTROL_SLIDER},
99 {"sliderex", CGUIControl::GUICONTROL_SETTINGS_SLIDER},
100 {"spincontrol", CGUIControl::GUICONTROL_SPIN},
101 {"spincontrolex", CGUIControl::GUICONTROL_SPINEX},
102 {"textbox", CGUIControl::GUICONTROL_TEXTBOX},
103 {"togglebutton", CGUIControl::GUICONTROL_TOGGLEBUTTON},
104 {"videowindow", CGUIControl::GUICONTROL_VIDEO},
105 {"visualisation", CGUIControl::GUICONTROL_VISUALISATION},
106 {"wraplist", CGUIControl::GUICONTAINER_WRAPLIST},
109 CGUIControl::GUICONTROLTYPES CGUIControlFactory::TranslateControlType(const std::string& type)
111 for (const ControlMapping& control : controls)
112 if (StringUtils::EqualsNoCase(type, control.name))
113 return control.type;
114 return CGUIControl::GUICONTROL_UNKNOWN;
117 std::string CGUIControlFactory::TranslateControlType(CGUIControl::GUICONTROLTYPES type)
119 for (const ControlMapping& control : controls)
120 if (type == control.type)
121 return control.name;
122 return "";
125 CGUIControlFactory::CGUIControlFactory(void) = default;
127 CGUIControlFactory::~CGUIControlFactory(void) = default;
129 bool CGUIControlFactory::GetIntRange(const TiXmlNode* pRootNode,
130 const char* strTag,
131 int& iMinValue,
132 int& iMaxValue,
133 int& iIntervalValue)
135 const TiXmlNode* pNode = pRootNode->FirstChild(strTag);
136 if (!pNode || !pNode->FirstChild())
137 return false;
138 iMinValue = atoi(pNode->FirstChild()->Value());
139 const char* maxValue = strchr(pNode->FirstChild()->Value(), ',');
140 if (maxValue)
142 maxValue++;
143 iMaxValue = atoi(maxValue);
145 const char* intervalValue = strchr(maxValue, ',');
146 if (intervalValue)
148 intervalValue++;
149 iIntervalValue = atoi(intervalValue);
153 return true;
156 bool CGUIControlFactory::GetFloatRange(const TiXmlNode* pRootNode,
157 const char* strTag,
158 float& fMinValue,
159 float& fMaxValue,
160 float& fIntervalValue)
162 const TiXmlNode* pNode = pRootNode->FirstChild(strTag);
163 if (!pNode || !pNode->FirstChild())
164 return false;
165 fMinValue = (float)atof(pNode->FirstChild()->Value());
166 const char* maxValue = strchr(pNode->FirstChild()->Value(), ',');
167 if (maxValue)
169 maxValue++;
170 fMaxValue = (float)atof(maxValue);
172 const char* intervalValue = strchr(maxValue, ',');
173 if (intervalValue)
175 intervalValue++;
176 fIntervalValue = (float)atof(intervalValue);
180 return true;
183 float CGUIControlFactory::ParsePosition(const char* pos, const float parentSize)
185 char* end = NULL;
186 float value = pos ? (float)strtod(pos, &end) : 0;
187 if (end)
189 if (*end == 'r')
190 value = parentSize - value;
191 else if (*end == '%')
192 value = value * parentSize / 100.0f;
194 return value;
197 bool CGUIControlFactory::GetPosition(const TiXmlNode* node,
198 const char* strTag,
199 const float parentSize,
200 float& value)
202 const TiXmlElement* pNode = node->FirstChildElement(strTag);
203 if (!pNode || !pNode->FirstChild())
204 return false;
206 value = ParsePosition(pNode->FirstChild()->Value(), parentSize);
207 return true;
210 bool CGUIControlFactory::GetDimension(const TiXmlNode* pRootNode,
211 const char* strTag,
212 const float parentSize,
213 float& value,
214 float& min)
216 const TiXmlElement* pNode = pRootNode->FirstChildElement(strTag);
217 if (!pNode || !pNode->FirstChild())
218 return false;
219 if (0 == StringUtils::CompareNoCase("auto", pNode->FirstChild()->Value(), 4))
220 { // auto-width - at least min must be set
221 value = ParsePosition(pNode->Attribute("max"), parentSize);
222 min = ParsePosition(pNode->Attribute("min"), parentSize);
223 if (!min)
224 min = 1;
225 return true;
227 value = ParsePosition(pNode->FirstChild()->Value(), parentSize);
228 return true;
231 bool CGUIControlFactory::GetDimensions(const TiXmlNode* node,
232 const char* leftTag,
233 const char* rightTag,
234 const char* centerLeftTag,
235 const char* centerRightTag,
236 const char* widthTag,
237 const float parentSize,
238 float& left,
239 float& width,
240 float& min_width)
242 float center = 0, right = 0;
244 // read from the XML
245 bool hasLeft = GetPosition(node, leftTag, parentSize, left);
246 bool hasCenter = GetPosition(node, centerLeftTag, parentSize, center);
247 if (!hasCenter && GetPosition(node, centerRightTag, parentSize, center))
249 center = parentSize - center;
250 hasCenter = true;
252 bool hasRight = false;
253 if (GetPosition(node, rightTag, parentSize, right))
255 right = parentSize - right;
256 hasRight = true;
258 bool hasWidth = GetDimension(node, widthTag, parentSize, width, min_width);
260 if (!hasLeft)
261 { // figure out position
262 if (hasCenter) // no left specified
264 if (hasWidth)
266 left = center - width / 2;
267 hasLeft = true;
269 else
271 if (hasRight)
273 width = (right - center) * 2;
274 left = right - width;
275 hasLeft = true;
279 else if (hasRight) // no left or centre
281 if (hasWidth)
283 left = right - width;
284 hasLeft = true;
288 if (!hasWidth)
290 if (hasRight)
292 width = std::max(0.0f, right - left); // if left=0, this fills to size of parent
293 hasLeft = true;
294 hasWidth = true;
296 else if (hasCenter)
298 if (hasLeft)
300 width = std::max(0.0f, (center - left) * 2);
301 hasWidth = true;
303 else if (center > 0 && center < parentSize)
304 { // centre given, so fill to edge of parent
305 width = std::max(0.0f, std::min(parentSize - center, center) * 2);
306 left = center - width / 2;
307 hasLeft = true;
308 hasWidth = true;
311 else if (hasLeft) // neither right nor center specified
313 width = std::max(0.0f, parentSize - left); // if left=0, this fills to parent
314 hasWidth = true;
317 return hasLeft && hasWidth;
320 bool CGUIControlFactory::GetAspectRatio(const TiXmlNode* pRootNode,
321 const char* strTag,
322 CAspectRatio& aspect)
324 std::string ratio;
325 const TiXmlElement* node = pRootNode->FirstChildElement(strTag);
326 if (!node || !node->FirstChild())
327 return false;
329 ratio = node->FirstChild()->Value();
330 if (StringUtils::EqualsNoCase(ratio, "keep"))
331 aspect.ratio = CAspectRatio::KEEP;
332 else if (StringUtils::EqualsNoCase(ratio, "scale"))
333 aspect.ratio = CAspectRatio::SCALE;
334 else if (StringUtils::EqualsNoCase(ratio, "center"))
335 aspect.ratio = CAspectRatio::CENTER;
336 else if (StringUtils::EqualsNoCase(ratio, "stretch"))
337 aspect.ratio = CAspectRatio::STRETCH;
339 const char* attribute = node->Attribute("align");
340 if (attribute)
342 std::string align(attribute);
343 if (StringUtils::EqualsNoCase(align, "center"))
344 aspect.align = ASPECT_ALIGN_CENTER | (aspect.align & ASPECT_ALIGNY_MASK);
345 else if (StringUtils::EqualsNoCase(align, "right"))
346 aspect.align = ASPECT_ALIGN_RIGHT | (aspect.align & ASPECT_ALIGNY_MASK);
347 else if (StringUtils::EqualsNoCase(align, "left"))
348 aspect.align = ASPECT_ALIGN_LEFT | (aspect.align & ASPECT_ALIGNY_MASK);
350 attribute = node->Attribute("aligny");
351 if (attribute)
353 std::string align(attribute);
354 if (StringUtils::EqualsNoCase(align, "center"))
355 aspect.align = ASPECT_ALIGNY_CENTER | (aspect.align & ASPECT_ALIGN_MASK);
356 else if (StringUtils::EqualsNoCase(align, "bottom"))
357 aspect.align = ASPECT_ALIGNY_BOTTOM | (aspect.align & ASPECT_ALIGN_MASK);
358 else if (StringUtils::EqualsNoCase(align, "top"))
359 aspect.align = ASPECT_ALIGNY_TOP | (aspect.align & ASPECT_ALIGN_MASK);
361 attribute = node->Attribute("scalediffuse");
362 if (attribute)
364 std::string scale(attribute);
365 if (StringUtils::EqualsNoCase(scale, "true") || StringUtils::EqualsNoCase(scale, "yes"))
366 aspect.scaleDiffuse = true;
367 else
368 aspect.scaleDiffuse = false;
370 return true;
373 bool CGUIControlFactory::GetInfoTexture(const TiXmlNode* pRootNode,
374 const char* strTag,
375 CTextureInfo& image,
376 GUIINFO::CGUIInfoLabel& info,
377 int parentID)
379 GetTexture(pRootNode, strTag, image);
380 image.filename = "";
381 GetInfoLabel(pRootNode, strTag, info, parentID);
382 return true;
385 bool CGUIControlFactory::GetTexture(const TiXmlNode* pRootNode,
386 const char* strTag,
387 CTextureInfo& image)
389 const TiXmlElement* pNode = pRootNode->FirstChildElement(strTag);
390 if (!pNode)
391 return false;
392 const char* border = pNode->Attribute("border");
393 if (border)
395 GetRectFromString(border, image.border);
396 const char* borderinfill = pNode->Attribute("infill");
397 image.m_infill = (!borderinfill || !StringUtils::EqualsNoCase(borderinfill, "false"));
399 image.orientation = 0;
400 const char* flipX = pNode->Attribute("flipx");
401 if (flipX && StringUtils::CompareNoCase(flipX, "true") == 0)
402 image.orientation = 1;
403 const char* flipY = pNode->Attribute("flipy");
404 if (flipY && StringUtils::CompareNoCase(flipY, "true") == 0)
405 image.orientation = 3 - image.orientation; // either 3 or 2
406 image.diffuse = XMLUtils::GetAttribute(pNode, "diffuse");
407 image.diffuseColor.Parse(XMLUtils::GetAttribute(pNode, "colordiffuse"), 0);
408 const char* background = pNode->Attribute("background");
409 if (background && StringUtils::CompareNoCase(background, "true", 4) == 0)
410 image.useLarge = true;
411 image.filename = pNode->FirstChild() ? pNode->FirstChild()->Value() : "";
412 return true;
415 void CGUIControlFactory::GetRectFromString(const std::string& string, CRect& rect)
417 // format is rect="left[,top,right,bottom]"
418 std::vector<std::string> strRect = StringUtils::Split(string, ',');
419 if (strRect.size() == 1)
421 rect.x1 = (float)atof(strRect[0].c_str());
422 rect.y1 = rect.x1;
423 rect.x2 = rect.x1;
424 rect.y2 = rect.x1;
426 else if (strRect.size() == 4)
428 rect.x1 = (float)atof(strRect[0].c_str());
429 rect.y1 = (float)atof(strRect[1].c_str());
430 rect.x2 = (float)atof(strRect[2].c_str());
431 rect.y2 = (float)atof(strRect[3].c_str());
435 bool CGUIControlFactory::GetAlignment(const TiXmlNode* pRootNode,
436 const char* strTag,
437 uint32_t& alignment)
439 const TiXmlNode* pNode = pRootNode->FirstChild(strTag);
440 if (!pNode || !pNode->FirstChild())
441 return false;
443 std::string strAlign = pNode->FirstChild()->Value();
444 if (strAlign == "right" || strAlign == "bottom")
445 alignment = XBFONT_RIGHT;
446 else if (strAlign == "center")
447 alignment = XBFONT_CENTER_X;
448 else if (strAlign == "justify")
449 alignment = XBFONT_JUSTIFIED;
450 else
451 alignment = XBFONT_LEFT;
452 return true;
455 bool CGUIControlFactory::GetAlignmentY(const TiXmlNode* pRootNode,
456 const char* strTag,
457 uint32_t& alignment)
459 const TiXmlNode* pNode = pRootNode->FirstChild(strTag);
460 if (!pNode || !pNode->FirstChild())
462 return false;
465 std::string strAlign = pNode->FirstChild()->Value();
467 alignment = 0;
468 if (strAlign == "center")
470 alignment = XBFONT_CENTER_Y;
473 return true;
476 bool CGUIControlFactory::GetConditionalVisibility(const TiXmlNode* control,
477 std::string& condition,
478 std::string& allowHiddenFocus)
480 const TiXmlElement* node = control->FirstChildElement("visible");
481 if (!node)
482 return false;
483 std::vector<std::string> conditions;
484 while (node)
486 const char* hidden = node->Attribute("allowhiddenfocus");
487 if (hidden)
488 allowHiddenFocus = hidden;
489 // add to our condition string
490 if (!node->NoChildren())
491 conditions.emplace_back(node->FirstChild()->Value());
492 node = node->NextSiblingElement("visible");
494 if (!conditions.size())
495 return false;
496 if (conditions.size() == 1)
497 condition = conditions[0];
498 else
499 { // multiple conditions should be anded together
500 condition = "[";
501 for (unsigned int i = 0; i < conditions.size() - 1; i++)
502 condition += conditions[i] + "] + [";
503 condition += conditions[conditions.size() - 1] + "]";
505 return true;
508 bool CGUIControlFactory::GetConditionalVisibility(const TiXmlNode* control, std::string& condition)
510 std::string allowHiddenFocus;
511 return GetConditionalVisibility(control, condition, allowHiddenFocus);
514 bool CGUIControlFactory::GetAnimations(TiXmlNode* control,
515 const CRect& rect,
516 int context,
517 std::vector<CAnimation>& animations)
519 TiXmlElement* node = control->FirstChildElement("animation");
520 bool ret = false;
521 if (node)
522 animations.clear();
523 while (node)
525 ret = true;
526 if (node->FirstChild())
528 CAnimation anim;
529 anim.Create(node, rect, context);
530 animations.push_back(anim);
531 if (StringUtils::CompareNoCase(node->FirstChild()->Value(), "VisibleChange") == 0)
532 { // add the hidden one as well
533 TiXmlElement hidden(*node);
534 hidden.FirstChild()->SetValue("hidden");
535 const char* start = hidden.Attribute("start");
536 const char* end = hidden.Attribute("end");
537 if (start && end)
539 std::string temp = end;
540 hidden.SetAttribute("end", start);
541 hidden.SetAttribute("start", temp.c_str());
543 else if (start)
544 hidden.SetAttribute("end", start);
545 else if (end)
546 hidden.SetAttribute("start", end);
547 CAnimation anim2;
548 anim2.Create(&hidden, rect, context);
549 animations.push_back(anim2);
552 node = node->NextSiblingElement("animation");
554 return ret;
557 bool CGUIControlFactory::GetActions(const TiXmlNode* pRootNode,
558 const char* strTag,
559 CGUIAction& actions)
561 actions.Reset();
562 const TiXmlElement* pElement = pRootNode->FirstChildElement(strTag);
563 while (pElement)
565 if (pElement->FirstChild())
567 actions.Append(
568 {XMLUtils::GetAttribute(pElement, "condition"), pElement->FirstChild()->Value()});
570 pElement = pElement->NextSiblingElement(strTag);
572 return actions.HasAnyActions();
575 bool CGUIControlFactory::GetHitRect(const TiXmlNode* control, CRect& rect, const CRect& parentRect)
577 const TiXmlElement* node = control->FirstChildElement("hitrect");
578 if (node)
580 rect.x1 = ParsePosition(node->Attribute("x"), parentRect.Width());
581 rect.y1 = ParsePosition(node->Attribute("y"), parentRect.Height());
582 if (node->Attribute("w"))
583 rect.x2 = (float)atof(node->Attribute("w")) + rect.x1;
584 else if (node->Attribute("right"))
585 rect.x2 = std::min(ParsePosition(node->Attribute("right"), parentRect.Width()), rect.x1);
586 if (node->Attribute("h"))
587 rect.y2 = (float)atof(node->Attribute("h")) + rect.y1;
588 else if (node->Attribute("bottom"))
589 rect.y2 = std::min(ParsePosition(node->Attribute("bottom"), parentRect.Height()), rect.y1);
590 return true;
592 return false;
595 bool CGUIControlFactory::GetScroller(const TiXmlNode* control,
596 const std::string& scrollerTag,
597 CScroller& scroller)
599 const TiXmlElement* node = control->FirstChildElement(scrollerTag);
600 if (node)
602 unsigned int scrollTime;
603 if (XMLUtils::GetUInt(control, scrollerTag.c_str(), scrollTime))
605 scroller = CScroller(scrollTime, CAnimEffect::GetTweener(node));
606 return true;
609 return false;
612 bool CGUIControlFactory::GetColor(const TiXmlNode* control,
613 const char* strTag,
614 KODI::UTILS::COLOR::Color& value)
616 const TiXmlElement* node = control->FirstChildElement(strTag);
617 if (node && node->FirstChild())
619 value = CServiceBroker::GetGUI()->GetColorManager().GetColor(node->FirstChild()->Value());
620 return true;
622 return false;
625 bool CGUIControlFactory::GetInfoColor(const TiXmlNode* control,
626 const char* strTag,
627 GUIINFO::CGUIInfoColor& value,
628 int parentID)
630 const TiXmlElement* node = control->FirstChildElement(strTag);
631 if (node && node->FirstChild())
633 value.Parse(node->FirstChild()->ValueStr(), parentID);
634 return true;
636 return false;
639 void CGUIControlFactory::GetInfoLabel(const TiXmlNode* pControlNode,
640 const std::string& labelTag,
641 GUIINFO::CGUIInfoLabel& infoLabel,
642 int parentID)
644 std::vector<GUIINFO::CGUIInfoLabel> labels;
645 GetInfoLabels(pControlNode, labelTag, labels, parentID);
646 if (labels.size())
647 infoLabel = labels[0];
650 bool CGUIControlFactory::GetInfoLabelFromElement(const TiXmlElement* element,
651 GUIINFO::CGUIInfoLabel& infoLabel,
652 int parentID)
654 if (!element || !element->FirstChild())
655 return false;
657 std::string label = element->FirstChild()->Value();
658 if (label.empty())
659 return false;
661 std::string fallback = XMLUtils::GetAttribute(element, "fallback");
662 if (StringUtils::IsNaturalNumber(label))
663 label = g_localizeStrings.Get(atoi(label.c_str()));
664 if (StringUtils::IsNaturalNumber(fallback))
665 fallback = g_localizeStrings.Get(atoi(fallback.c_str()));
666 else
667 g_charsetConverter.unknownToUTF8(fallback);
668 infoLabel.SetLabel(label, fallback, parentID);
669 return true;
672 void CGUIControlFactory::GetInfoLabels(const TiXmlNode* pControlNode,
673 const std::string& labelTag,
674 std::vector<GUIINFO::CGUIInfoLabel>& infoLabels,
675 int parentID)
677 // we can have the following infolabels:
678 // 1. <number>1234</number> -> direct number
679 // 2. <label>number</label> -> lookup in localizestrings
680 // 3. <label fallback="blah">$LOCALIZE(blah) $INFO(blah)</label> -> infolabel with given fallback
681 // 4. <info>ListItem.Album</info> (uses <label> as fallback)
682 int labelNumber = 0;
683 if (XMLUtils::GetInt(pControlNode, "number", labelNumber))
685 std::string label = std::to_string(labelNumber);
686 infoLabels.emplace_back(label);
687 return; // done
689 const TiXmlElement* labelNode = pControlNode->FirstChildElement(labelTag);
690 while (labelNode)
692 GUIINFO::CGUIInfoLabel label;
693 if (GetInfoLabelFromElement(labelNode, label, parentID))
694 infoLabels.push_back(label);
695 labelNode = labelNode->NextSiblingElement(labelTag);
697 const TiXmlNode* infoNode = pControlNode->FirstChild("info");
698 if (infoNode)
699 { // <info> nodes override <label>'s (backward compatibility)
700 std::string fallback;
701 if (infoLabels.size())
702 fallback = infoLabels[0].GetLabel(0);
703 infoLabels.clear();
704 while (infoNode)
706 if (infoNode->FirstChild())
708 std::string info = StringUtils::Format("$INFO[{}]", infoNode->FirstChild()->Value());
709 infoLabels.emplace_back(info, fallback, parentID);
711 infoNode = infoNode->NextSibling("info");
716 // Convert a string to a GUI label, by translating/parsing the label for localisable strings
717 std::string CGUIControlFactory::FilterLabel(const std::string& label)
719 std::string viewLabel = label;
720 if (StringUtils::IsNaturalNumber(viewLabel))
721 viewLabel = g_localizeStrings.Get(atoi(label.c_str()));
722 else
723 g_charsetConverter.unknownToUTF8(viewLabel);
724 return viewLabel;
727 bool CGUIControlFactory::GetString(const TiXmlNode* pRootNode,
728 const char* strTag,
729 std::string& text)
731 if (!XMLUtils::GetString(pRootNode, strTag, text))
732 return false;
733 if (StringUtils::IsNaturalNumber(text))
734 text = g_localizeStrings.Get(atoi(text.c_str()));
735 return true;
738 std::string CGUIControlFactory::GetType(const TiXmlElement* pControlNode)
740 std::string type = XMLUtils::GetAttribute(pControlNode, "type");
741 if (type.empty()) // backward compatibility - not desired
742 XMLUtils::GetString(pControlNode, "type", type);
743 return type;
746 bool CGUIControlFactory::GetMovingSpeedConfig(const TiXmlNode* pRootNode,
747 const char* strTag,
748 KODI::UTILS::MOVING_SPEED::MapEventConfig& movingSpeedCfg)
750 const TiXmlElement* msNode = pRootNode->FirstChildElement(strTag);
751 if (!msNode)
752 return false;
754 float globalAccel{StringUtils::ToFloat(XMLUtils::GetAttribute(msNode, "acceleration"))};
755 float globalMaxVel{StringUtils::ToFloat(XMLUtils::GetAttribute(msNode, "maxvelocity"))};
756 uint32_t globalResetTimeout{
757 StringUtils::ToUint32(XMLUtils::GetAttribute(msNode, "resettimeout"))};
758 float globalDelta{StringUtils::ToFloat(XMLUtils::GetAttribute(msNode, "delta"))};
760 for (const TiXmlElement* configElement{msNode->FirstChildElement("eventconfig")}; configElement;
761 configElement = configElement->NextSiblingElement("eventconfig"))
763 const char* eventType = configElement->Attribute("type");
764 if (!eventType)
766 CLog::LogF(LOGERROR, "Failed to parse XML \"eventconfig\" tag missing \"type\" attribute");
767 continue;
770 const char* accelerationStr{configElement->Attribute("acceleration")};
771 float acceleration = accelerationStr ? StringUtils::ToFloat(accelerationStr) : globalAccel;
773 const char* maxVelocityStr{configElement->Attribute("maxvelocity")};
774 float maxVelocity = maxVelocityStr ? StringUtils::ToFloat(maxVelocityStr) : globalMaxVel;
776 const char* resetTimeoutStr{configElement->Attribute("resettimeout")};
777 uint32_t resetTimeout =
778 resetTimeoutStr ? StringUtils::ToUint32(resetTimeoutStr) : globalResetTimeout;
780 const char* deltaStr{configElement->Attribute("delta")};
781 float delta = deltaStr ? StringUtils::ToFloat(deltaStr) : globalDelta;
783 KODI::UTILS::MOVING_SPEED::EventCfg eventCfg{acceleration, maxVelocity, resetTimeout, delta};
784 movingSpeedCfg.emplace(KODI::UTILS::MOVING_SPEED::ParseEventType(eventType), eventCfg);
786 return true;
789 CGUIControl* CGUIControlFactory::Create(int parentID,
790 const CRect& rect,
791 TiXmlElement* pControlNode,
792 bool insideContainer)
794 // get the control type
795 std::string strType = GetType(pControlNode);
796 CGUIControl::GUICONTROLTYPES type = TranslateControlType(strType);
798 int id = 0;
799 float posX = 0, posY = 0;
800 float width = 0, height = 0;
801 float minHeight = 0, minWidth = 0;
803 CGUIControl::ActionMap actions;
805 int pageControl = 0;
806 GUIINFO::CGUIInfoColor colorDiffuse(0xFFFFFFFF);
807 GUIINFO::CGUIInfoColor colorBox(0xFF000000);
808 int defaultControl = 0;
809 bool defaultAlways = false;
810 std::string strTmp;
811 int singleInfo = 0;
812 int singleInfo2 = 0;
813 std::string strLabel;
814 int iUrlSet = 0;
815 std::string toggleSelect;
817 float spinWidth = 16;
818 float spinHeight = 16;
819 float spinPosX = 0, spinPosY = 0;
820 std::string strSubType;
821 int iType = SPIN_CONTROL_TYPE_TEXT;
822 int iMin = 0;
823 int iMax = 100;
824 int iInterval = 1;
825 float fMin = 0.0f;
826 float fMax = 1.0f;
827 float fInterval = 0.1f;
828 bool bReverse = true;
829 bool bReveal = false;
830 CTextureInfo textureBackground, textureLeft, textureRight, textureMid, textureOverlay;
831 CTextureInfo textureNib, textureNibFocus, textureNibDisabled, textureBar, textureBarFocus,
832 textureBarDisabled;
833 CTextureInfo textureUp, textureDown;
834 CTextureInfo textureUpFocus, textureDownFocus;
835 CTextureInfo textureUpDisabled, textureDownDisabled;
836 CTextureInfo texture, borderTexture;
837 GUIINFO::CGUIInfoLabel textureFile;
838 CTextureInfo textureFocus, textureNoFocus;
839 CTextureInfo textureAltFocus, textureAltNoFocus;
840 CTextureInfo textureRadioOnFocus, textureRadioOnNoFocus;
841 CTextureInfo textureRadioOffFocus, textureRadioOffNoFocus;
842 CTextureInfo textureRadioOnDisabled, textureRadioOffDisabled;
843 CTextureInfo textureProgressIndicator;
844 CTextureInfo textureColorMask, textureColorDisabledMask;
846 GUIINFO::CGUIInfoLabel texturePath;
847 CRect borderSize;
849 float sliderWidth = 150, sliderHeight = 16;
850 CPoint offset;
852 bool bHasPath = false;
853 CGUIAction clickActions;
854 CGUIAction altclickActions;
855 CGUIAction focusActions;
856 CGUIAction unfocusActions;
857 CGUIAction textChangeActions;
858 std::string strTitle = "";
859 std::string strRSSTags = "";
861 float buttonGap = 5;
862 int iMovementRange = 0;
863 CAspectRatio aspect;
864 std::string allowHiddenFocus;
865 std::string enableCondition;
867 std::vector<CAnimation> animations;
869 CGUIControl::GUISCROLLVALUE scrollValue = CGUIControl::FOCUS;
870 bool bPulse = true;
871 unsigned int timePerImage = 0;
872 unsigned int fadeTime = 0;
873 unsigned int timeToPauseAtEnd = 0;
874 bool randomized = false;
875 bool loop = true;
876 bool wrapMultiLine = false;
877 ORIENTATION orientation = VERTICAL;
878 bool showOnePage = true;
879 bool scrollOut = true;
880 int preloadItems = 0;
882 CLabelInfo labelInfo, labelInfoMono;
884 GUIINFO::CGUIInfoColor hitColor(0xFFFFFFFF);
885 GUIINFO::CGUIInfoColor textColor3;
886 GUIINFO::CGUIInfoColor headlineColor;
888 float radioWidth = 0;
889 float radioHeight = 0;
890 float radioPosX = 0;
891 float radioPosY = 0;
893 float colorWidth = 0;
894 float colorHeight = 0;
895 float colorPosX = 0;
896 float colorPosY = 0;
898 std::string altLabel;
899 std::string strLabel2;
900 std::string action;
902 int focusPosition = 0;
903 int scrollTime = 200;
904 int timeBlocks = 36;
905 int rulerUnit = 12;
906 bool useControlCoords = false;
907 bool renderFocusedLast = false;
909 CRect hitRect;
910 CPoint camera;
911 float stereo = 0.f;
912 bool hasCamera = false;
913 bool resetOnLabelChange = true;
914 bool bPassword = false;
915 std::string visibleCondition;
917 KODI::UTILS::MOVING_SPEED::MapEventConfig movingSpeedCfg;
919 /////////////////////////////////////////////////////////////////////////////
920 // Read control properties from XML
923 if (!pControlNode->Attribute("id", &id))
924 XMLUtils::GetInt(pControlNode, "id", id); // backward compatibility - not desired
925 //! @todo Perhaps we should check here whether id is valid for focusable controls
926 //! such as buttons etc. For labels/fadelabels/images it does not matter
928 GetAlignment(pControlNode, "align", labelInfo.align);
929 if (!GetDimensions(pControlNode, "left", "right", "centerleft", "centerright", "width",
930 rect.Width(), posX, width, minWidth))
931 { // didn't get 2 dimensions, so test for old <posx> as well
932 if (GetPosition(pControlNode, "posx", rect.Width(), posX))
933 { // <posx> available, so use it along with any hacks we used to support
934 if (!insideContainer && type == CGUIControl::GUICONTROL_LABEL &&
935 (labelInfo.align & XBFONT_RIGHT))
936 posX -= width;
938 if (!width) // no width specified, so compute from parent
939 width = std::max(rect.Width() - posX, 0.0f);
941 if (!GetDimensions(pControlNode, "top", "bottom", "centertop", "centerbottom", "height",
942 rect.Height(), posY, height, minHeight))
944 GetPosition(pControlNode, "posy", rect.Height(), posY);
945 if (!height)
946 height = std::max(rect.Height() - posY, 0.0f);
949 XMLUtils::GetFloat(pControlNode, "offsetx", offset.x);
950 XMLUtils::GetFloat(pControlNode, "offsety", offset.y);
952 hitRect.SetRect(posX, posY, posX + width, posY + height);
953 GetHitRect(pControlNode, hitRect, rect);
955 GetInfoColor(pControlNode, "hitrectcolor", hitColor, parentID);
957 GetActions(pControlNode, "onup", actions[ACTION_MOVE_UP]);
958 GetActions(pControlNode, "ondown", actions[ACTION_MOVE_DOWN]);
959 GetActions(pControlNode, "onleft", actions[ACTION_MOVE_LEFT]);
960 GetActions(pControlNode, "onright", actions[ACTION_MOVE_RIGHT]);
961 GetActions(pControlNode, "onnext", actions[ACTION_NEXT_CONTROL]);
962 GetActions(pControlNode, "onprev", actions[ACTION_PREV_CONTROL]);
963 GetActions(pControlNode, "onback", actions[ACTION_NAV_BACK]);
964 GetActions(pControlNode, "oninfo", actions[ACTION_SHOW_INFO]);
966 if (XMLUtils::GetInt(pControlNode, "defaultcontrol", defaultControl))
968 const char* always = pControlNode->FirstChildElement("defaultcontrol")->Attribute("always");
969 if (always && StringUtils::CompareNoCase(always, "true", 4) == 0)
970 defaultAlways = true;
972 XMLUtils::GetInt(pControlNode, "pagecontrol", pageControl);
974 GetInfoColor(pControlNode, "colordiffuse", colorDiffuse, parentID);
975 GetInfoColor(pControlNode, "colorbox", colorBox, parentID);
977 GetConditionalVisibility(pControlNode, visibleCondition, allowHiddenFocus);
978 XMLUtils::GetString(pControlNode, "enable", enableCondition);
980 CRect animRect(posX, posY, posX + width, posY + height);
981 GetAnimations(pControlNode, animRect, parentID, animations);
983 GetInfoColor(pControlNode, "textcolor", labelInfo.textColor, parentID);
984 GetInfoColor(pControlNode, "focusedcolor", labelInfo.focusedColor, parentID);
985 GetInfoColor(pControlNode, "disabledcolor", labelInfo.disabledColor, parentID);
986 GetInfoColor(pControlNode, "shadowcolor", labelInfo.shadowColor, parentID);
987 GetInfoColor(pControlNode, "selectedcolor", labelInfo.selectedColor, parentID);
988 GetInfoColor(pControlNode, "invalidcolor", labelInfo.invalidColor, parentID);
989 XMLUtils::GetFloat(pControlNode, "textoffsetx", labelInfo.offsetX);
990 XMLUtils::GetFloat(pControlNode, "textoffsety", labelInfo.offsetY);
991 int angle = 0; // use the negative angle to compensate for our vertically flipped cartesian plane
992 if (XMLUtils::GetInt(pControlNode, "angle", angle))
993 labelInfo.angle = (float)-angle;
994 std::string strFont, strMonoFont;
995 if (XMLUtils::GetString(pControlNode, "font", strFont))
996 labelInfo.font = g_fontManager.GetFont(strFont);
997 XMLUtils::GetString(pControlNode, "monofont", strMonoFont);
998 uint32_t alignY = 0;
999 if (GetAlignmentY(pControlNode, "aligny", alignY))
1000 labelInfo.align |= alignY;
1001 if (XMLUtils::GetFloat(pControlNode, "textwidth", labelInfo.width))
1002 labelInfo.align |= XBFONT_TRUNCATED;
1004 GetActions(pControlNode, "onclick", clickActions);
1005 GetActions(pControlNode, "ontextchange", textChangeActions);
1006 GetActions(pControlNode, "onfocus", focusActions);
1007 GetActions(pControlNode, "onunfocus", unfocusActions);
1008 focusActions.EnableSendThreadMessageMode();
1009 unfocusActions.EnableSendThreadMessageMode();
1010 GetActions(pControlNode, "altclick", altclickActions);
1012 std::string infoString;
1013 if (XMLUtils::GetString(pControlNode, "info", infoString))
1014 singleInfo = CServiceBroker::GetGUI()->GetInfoManager().TranslateString(infoString);
1015 if (XMLUtils::GetString(pControlNode, "info2", infoString))
1016 singleInfo2 = CServiceBroker::GetGUI()->GetInfoManager().TranslateString(infoString);
1018 GetTexture(pControlNode, "texturefocus", textureFocus);
1019 GetTexture(pControlNode, "texturenofocus", textureNoFocus);
1020 GetTexture(pControlNode, "alttexturefocus", textureAltFocus);
1021 GetTexture(pControlNode, "alttexturenofocus", textureAltNoFocus);
1023 XMLUtils::GetString(pControlNode, "usealttexture", toggleSelect);
1024 XMLUtils::GetString(pControlNode, "selected", toggleSelect);
1026 XMLUtils::GetBoolean(pControlNode, "haspath", bHasPath);
1028 GetTexture(pControlNode, "textureup", textureUp);
1029 GetTexture(pControlNode, "texturedown", textureDown);
1030 GetTexture(pControlNode, "textureupfocus", textureUpFocus);
1031 GetTexture(pControlNode, "texturedownfocus", textureDownFocus);
1032 GetTexture(pControlNode, "textureupdisabled", textureUpDisabled);
1033 GetTexture(pControlNode, "texturedowndisabled", textureDownDisabled);
1035 XMLUtils::GetFloat(pControlNode, "spinwidth", spinWidth);
1036 XMLUtils::GetFloat(pControlNode, "spinheight", spinHeight);
1037 XMLUtils::GetFloat(pControlNode, "spinposx", spinPosX);
1038 XMLUtils::GetFloat(pControlNode, "spinposy", spinPosY);
1040 XMLUtils::GetFloat(pControlNode, "sliderwidth", sliderWidth);
1041 XMLUtils::GetFloat(pControlNode, "sliderheight", sliderHeight);
1042 if (!GetTexture(pControlNode, "textureradioonfocus", textureRadioOnFocus) ||
1043 !GetTexture(pControlNode, "textureradioonnofocus", textureRadioOnNoFocus))
1045 GetTexture(pControlNode, "textureradiofocus", textureRadioOnFocus); // backward compatibility
1046 GetTexture(pControlNode, "textureradioon", textureRadioOnFocus);
1047 textureRadioOnNoFocus = textureRadioOnFocus;
1049 if (!GetTexture(pControlNode, "textureradioofffocus", textureRadioOffFocus) ||
1050 !GetTexture(pControlNode, "textureradiooffnofocus", textureRadioOffNoFocus))
1052 GetTexture(pControlNode, "textureradionofocus", textureRadioOffFocus); // backward compatibility
1053 GetTexture(pControlNode, "textureradiooff", textureRadioOffFocus);
1054 textureRadioOffNoFocus = textureRadioOffFocus;
1056 GetTexture(pControlNode, "textureradioondisabled", textureRadioOnDisabled);
1057 GetTexture(pControlNode, "textureradiooffdisabled", textureRadioOffDisabled);
1058 GetTexture(pControlNode, "texturesliderbackground", textureBackground);
1059 GetTexture(pControlNode, "texturesliderbar", textureBar);
1060 GetTexture(pControlNode, "texturesliderbarfocus", textureBarFocus);
1061 if (!GetTexture(pControlNode, "texturesliderbardisabled", textureBarDisabled))
1062 GetTexture(pControlNode, "texturesliderbar", textureBarDisabled); // backward compatibility
1063 GetTexture(pControlNode, "textureslidernib", textureNib);
1064 GetTexture(pControlNode, "textureslidernibfocus", textureNibFocus);
1065 if (!GetTexture(pControlNode, "textureslidernibdisabled", textureNibDisabled))
1066 GetTexture(pControlNode, "textureslidernib", textureNibDisabled); // backward compatibility
1068 GetTexture(pControlNode, "texturecolormask", textureColorMask);
1069 GetTexture(pControlNode, "texturecolordisabledmask", textureColorDisabledMask);
1071 XMLUtils::GetString(pControlNode, "title", strTitle);
1072 XMLUtils::GetString(pControlNode, "tagset", strRSSTags);
1073 GetInfoColor(pControlNode, "headlinecolor", headlineColor, parentID);
1074 GetInfoColor(pControlNode, "titlecolor", textColor3, parentID);
1076 if (XMLUtils::GetString(pControlNode, "subtype", strSubType))
1078 StringUtils::ToLower(strSubType);
1080 if (strSubType == "int")
1081 iType = SPIN_CONTROL_TYPE_INT;
1082 else if (strSubType == "page")
1083 iType = SPIN_CONTROL_TYPE_PAGE;
1084 else if (strSubType == "float")
1085 iType = SPIN_CONTROL_TYPE_FLOAT;
1086 else
1087 iType = SPIN_CONTROL_TYPE_TEXT;
1090 if (!GetIntRange(pControlNode, "range", iMin, iMax, iInterval))
1092 GetFloatRange(pControlNode, "range", fMin, fMax, fInterval);
1095 XMLUtils::GetBoolean(pControlNode, "reverse", bReverse);
1096 XMLUtils::GetBoolean(pControlNode, "reveal", bReveal);
1098 GetTexture(pControlNode, "texturebg", textureBackground);
1099 GetTexture(pControlNode, "lefttexture", textureLeft);
1100 GetTexture(pControlNode, "midtexture", textureMid);
1101 GetTexture(pControlNode, "righttexture", textureRight);
1102 GetTexture(pControlNode, "overlaytexture", textureOverlay);
1104 // the <texture> tag can be overridden by the <info> tag
1105 GetInfoTexture(pControlNode, "texture", texture, textureFile, parentID);
1107 GetTexture(pControlNode, "bordertexture", borderTexture);
1109 // fade label can have a whole bunch, but most just have one
1110 std::vector<GUIINFO::CGUIInfoLabel> infoLabels;
1111 GetInfoLabels(pControlNode, "label", infoLabels, parentID);
1113 GetString(pControlNode, "label", strLabel);
1114 GetString(pControlNode, "altlabel", altLabel);
1115 GetString(pControlNode, "label2", strLabel2);
1117 XMLUtils::GetBoolean(pControlNode, "wrapmultiline", wrapMultiLine);
1118 XMLUtils::GetInt(pControlNode, "urlset", iUrlSet);
1120 if (XMLUtils::GetString(pControlNode, "orientation", strTmp))
1122 StringUtils::ToLower(strTmp);
1123 if (strTmp == "horizontal")
1124 orientation = HORIZONTAL;
1126 XMLUtils::GetFloat(pControlNode, "itemgap", buttonGap);
1127 XMLUtils::GetInt(pControlNode, "movement", iMovementRange);
1128 GetAspectRatio(pControlNode, "aspectratio", aspect);
1130 bool alwaysScroll;
1131 if (XMLUtils::GetBoolean(pControlNode, "scroll", alwaysScroll))
1132 scrollValue = alwaysScroll ? CGUIControl::ALWAYS : CGUIControl::NEVER;
1134 XMLUtils::GetBoolean(pControlNode, "pulseonselect", bPulse);
1135 XMLUtils::GetInt(pControlNode, "timeblocks", timeBlocks);
1136 XMLUtils::GetInt(pControlNode, "rulerunit", rulerUnit);
1137 GetTexture(pControlNode, "progresstexture", textureProgressIndicator);
1139 GetInfoTexture(pControlNode, "imagepath", texture, texturePath, parentID);
1141 XMLUtils::GetUInt(pControlNode, "timeperimage", timePerImage);
1142 XMLUtils::GetUInt(pControlNode, "fadetime", fadeTime);
1143 XMLUtils::GetUInt(pControlNode, "pauseatend", timeToPauseAtEnd);
1144 XMLUtils::GetBoolean(pControlNode, "randomize", randomized);
1145 XMLUtils::GetBoolean(pControlNode, "loop", loop);
1146 XMLUtils::GetBoolean(pControlNode, "scrollout", scrollOut);
1148 XMLUtils::GetFloat(pControlNode, "radiowidth", radioWidth);
1149 XMLUtils::GetFloat(pControlNode, "radioheight", radioHeight);
1150 XMLUtils::GetFloat(pControlNode, "radioposx", radioPosX);
1151 XMLUtils::GetFloat(pControlNode, "radioposy", radioPosY);
1153 XMLUtils::GetFloat(pControlNode, "colorwidth", colorWidth);
1154 XMLUtils::GetFloat(pControlNode, "colorheight", colorHeight);
1155 XMLUtils::GetFloat(pControlNode, "colorposx", colorPosX);
1156 XMLUtils::GetFloat(pControlNode, "colorposy", colorPosY);
1158 std::string borderStr;
1159 if (XMLUtils::GetString(pControlNode, "bordersize", borderStr))
1160 GetRectFromString(borderStr, borderSize);
1162 XMLUtils::GetBoolean(pControlNode, "showonepage", showOnePage);
1163 XMLUtils::GetInt(pControlNode, "focusposition", focusPosition);
1164 XMLUtils::GetInt(pControlNode, "scrolltime", scrollTime);
1165 XMLUtils::GetInt(pControlNode, "preloaditems", preloadItems, 0, 2);
1167 XMLUtils::GetBoolean(pControlNode, "usecontrolcoords", useControlCoords);
1168 XMLUtils::GetBoolean(pControlNode, "renderfocusedlast", renderFocusedLast);
1169 XMLUtils::GetBoolean(pControlNode, "resetonlabelchange", resetOnLabelChange);
1171 XMLUtils::GetBoolean(pControlNode, "password", bPassword);
1173 // view type
1174 VIEW_TYPE viewType = VIEW_TYPE_NONE;
1175 std::string viewLabel;
1176 if (type == CGUIControl::GUICONTAINER_PANEL)
1178 viewType = VIEW_TYPE_ICON;
1179 viewLabel = g_localizeStrings.Get(536);
1181 else if (type == CGUIControl::GUICONTAINER_LIST)
1183 viewType = VIEW_TYPE_LIST;
1184 viewLabel = g_localizeStrings.Get(535);
1186 else
1188 viewType = VIEW_TYPE_WRAP;
1189 viewLabel = g_localizeStrings.Get(541);
1191 TiXmlElement* itemElement = pControlNode->FirstChildElement("viewtype");
1192 if (itemElement && itemElement->FirstChild())
1194 std::string type = itemElement->FirstChild()->Value();
1195 if (type == "list")
1196 viewType = VIEW_TYPE_LIST;
1197 else if (type == "icon")
1198 viewType = VIEW_TYPE_ICON;
1199 else if (type == "biglist")
1200 viewType = VIEW_TYPE_BIG_LIST;
1201 else if (type == "bigicon")
1202 viewType = VIEW_TYPE_BIG_ICON;
1203 else if (type == "wide")
1204 viewType = VIEW_TYPE_WIDE;
1205 else if (type == "bigwide")
1206 viewType = VIEW_TYPE_BIG_WIDE;
1207 else if (type == "wrap")
1208 viewType = VIEW_TYPE_WRAP;
1209 else if (type == "bigwrap")
1210 viewType = VIEW_TYPE_BIG_WRAP;
1211 else if (type == "info")
1212 viewType = VIEW_TYPE_INFO;
1213 else if (type == "biginfo")
1214 viewType = VIEW_TYPE_BIG_INFO;
1215 const char* label = itemElement->Attribute("label");
1216 if (label)
1217 viewLabel = GUIINFO::CGUIInfoLabel::GetLabel(FilterLabel(label), INFO::DEFAULT_CONTEXT);
1220 TiXmlElement* cam = pControlNode->FirstChildElement("camera");
1221 if (cam)
1223 hasCamera = true;
1224 camera.x = ParsePosition(cam->Attribute("x"), width);
1225 camera.y = ParsePosition(cam->Attribute("y"), height);
1228 if (XMLUtils::GetFloat(pControlNode, "depth", stereo))
1229 stereo = std::max(-1.f, std::min(1.f, stereo));
1231 XMLUtils::GetInt(pControlNode, "scrollspeed", labelInfo.scrollSpeed);
1233 GetString(pControlNode, "scrollsuffix", labelInfo.scrollSuffix);
1235 XMLUtils::GetString(pControlNode, "action", action);
1237 GetMovingSpeedConfig(pControlNode, "movingspeed", movingSpeedCfg);
1239 /////////////////////////////////////////////////////////////////////////////
1240 // Instantiate a new control using the properties gathered above
1243 CGUIControl* control = NULL;
1244 switch (type)
1246 case CGUIControl::GUICONTROL_GROUP:
1248 if (insideContainer)
1250 control = new CGUIListGroup(parentID, id, posX, posY, width, height);
1252 else
1254 control = new CGUIControlGroup(parentID, id, posX, posY, width, height);
1255 static_cast<CGUIControlGroup*>(control)->SetDefaultControl(defaultControl, defaultAlways);
1256 static_cast<CGUIControlGroup*>(control)->SetRenderFocusedLast(renderFocusedLast);
1258 break;
1260 case CGUIControl::GUICONTROL_GROUPLIST:
1262 CScroller scroller;
1263 GetScroller(pControlNode, "scrolltime", scroller);
1265 control =
1266 new CGUIControlGroupList(parentID, id, posX, posY, width, height, buttonGap, pageControl,
1267 orientation, useControlCoords, labelInfo.align, scroller);
1268 static_cast<CGUIControlGroup*>(control)->SetDefaultControl(defaultControl, defaultAlways);
1269 static_cast<CGUIControlGroup*>(control)->SetRenderFocusedLast(renderFocusedLast);
1270 static_cast<CGUIControlGroupList*>(control)->SetMinSize(minWidth, minHeight);
1272 break;
1274 case CGUIControl::GUICONTROL_LABEL:
1276 static const GUIINFO::CGUIInfoLabel empty;
1277 const GUIINFO::CGUIInfoLabel& content = !infoLabels.empty() ? infoLabels[0] : empty;
1278 if (insideContainer)
1279 { // inside lists we use CGUIListLabel
1280 control = new CGUIListLabel(parentID, id, posX, posY, width, height, labelInfo, content,
1281 scrollValue);
1283 else
1285 control = new CGUILabelControl(parentID, id, posX, posY, width, height, labelInfo,
1286 wrapMultiLine, bHasPath);
1287 static_cast<CGUILabelControl*>(control)->SetInfo(content);
1288 static_cast<CGUILabelControl*>(control)->SetWidthControl(
1289 minWidth, (scrollValue == CGUIControl::ALWAYS));
1292 break;
1294 case CGUIControl::GUICONTROL_EDIT:
1296 control = new CGUIEditControl(parentID, id, posX, posY, width, height, textureFocus,
1297 textureNoFocus, labelInfo, strLabel);
1299 GUIINFO::CGUIInfoLabel hint_text;
1300 GetInfoLabel(pControlNode, "hinttext", hint_text, parentID);
1301 static_cast<CGUIEditControl*>(control)->SetHint(hint_text);
1303 if (bPassword)
1304 static_cast<CGUIEditControl*>(control)->SetInputType(CGUIEditControl::INPUT_TYPE_PASSWORD,
1306 static_cast<CGUIEditControl*>(control)->SetTextChangeActions(textChangeActions);
1308 break;
1310 case CGUIControl::GUICONTROL_VIDEO:
1312 control = new CGUIVideoControl(parentID, id, posX, posY, width, height);
1313 break;
1315 case CGUIControl::GUICONTROL_GAME:
1317 control = new RETRO::CGUIGameControl(parentID, id, posX, posY, width, height);
1319 GUIINFO::CGUIInfoLabel videoFilter;
1320 GetInfoLabel(pControlNode, "videofilter", videoFilter, parentID);
1321 static_cast<RETRO::CGUIGameControl*>(control)->SetVideoFilter(videoFilter);
1323 GUIINFO::CGUIInfoLabel stretchMode;
1324 GetInfoLabel(pControlNode, "stretchmode", stretchMode, parentID);
1325 static_cast<RETRO::CGUIGameControl*>(control)->SetStretchMode(stretchMode);
1327 GUIINFO::CGUIInfoLabel rotation;
1328 GetInfoLabel(pControlNode, "rotation", rotation, parentID);
1329 static_cast<RETRO::CGUIGameControl*>(control)->SetRotation(rotation);
1331 GUIINFO::CGUIInfoLabel pixels;
1332 GetInfoLabel(pControlNode, "pixels", pixels, parentID);
1333 static_cast<RETRO::CGUIGameControl*>(control)->SetPixels(pixels);
1335 break;
1337 case CGUIControl::GUICONTROL_FADELABEL:
1339 control =
1340 new CGUIFadeLabelControl(parentID, id, posX, posY, width, height, labelInfo, scrollOut,
1341 timeToPauseAtEnd, resetOnLabelChange, randomized);
1343 static_cast<CGUIFadeLabelControl*>(control)->SetInfo(infoLabels);
1345 // check whether or not a scroll tag was specified.
1346 if (scrollValue != CGUIControl::FOCUS)
1347 static_cast<CGUIFadeLabelControl*>(control)->SetScrolling(scrollValue ==
1348 CGUIControl::ALWAYS);
1350 break;
1352 case CGUIControl::GUICONTROL_RSS:
1354 control = new CGUIRSSControl(parentID, id, posX, posY, width, height, labelInfo, textColor3,
1355 headlineColor, strRSSTags);
1356 RssUrls::const_iterator iter = CRssManager::GetInstance().GetUrls().find(iUrlSet);
1357 if (iter != CRssManager::GetInstance().GetUrls().end())
1358 static_cast<CGUIRSSControl*>(control)->SetUrlSet(iUrlSet);
1360 break;
1362 case CGUIControl::GUICONTROL_BUTTON:
1364 control = new CGUIButtonControl(parentID, id, posX, posY, width, height, textureFocus,
1365 textureNoFocus, labelInfo, wrapMultiLine);
1367 CGUIButtonControl* bcontrol = static_cast<CGUIButtonControl*>(control);
1368 bcontrol->SetLabel(strLabel);
1369 bcontrol->SetLabel2(strLabel2);
1370 bcontrol->SetMinWidth(minWidth);
1371 bcontrol->SetClickActions(clickActions);
1372 bcontrol->SetFocusActions(focusActions);
1373 bcontrol->SetUnFocusActions(unfocusActions);
1375 break;
1377 case CGUIControl::GUICONTROL_TOGGLEBUTTON:
1379 control = new CGUIToggleButtonControl(parentID, id, posX, posY, width, height, textureFocus,
1380 textureNoFocus, textureAltFocus, textureAltNoFocus,
1381 labelInfo, wrapMultiLine);
1383 CGUIToggleButtonControl* tcontrol = static_cast<CGUIToggleButtonControl*>(control);
1384 tcontrol->SetLabel(strLabel);
1385 tcontrol->SetAltLabel(altLabel);
1386 tcontrol->SetMinWidth(minWidth);
1387 tcontrol->SetClickActions(clickActions);
1388 tcontrol->SetAltClickActions(altclickActions);
1389 tcontrol->SetFocusActions(focusActions);
1390 tcontrol->SetUnFocusActions(unfocusActions);
1391 tcontrol->SetToggleSelect(toggleSelect);
1393 break;
1395 case CGUIControl::GUICONTROL_RADIO:
1397 control = new CGUIRadioButtonControl(
1398 parentID, id, posX, posY, width, height, textureFocus, textureNoFocus, labelInfo,
1399 textureRadioOnFocus, textureRadioOnNoFocus, textureRadioOffFocus, textureRadioOffNoFocus,
1400 textureRadioOnDisabled, textureRadioOffDisabled);
1402 CGUIRadioButtonControl* rcontrol = static_cast<CGUIRadioButtonControl*>(control);
1403 rcontrol->SetLabel(strLabel);
1404 rcontrol->SetLabel2(strLabel2);
1405 rcontrol->SetRadioDimensions(radioPosX, radioPosY, radioWidth, radioHeight);
1406 rcontrol->SetToggleSelect(toggleSelect);
1407 rcontrol->SetClickActions(clickActions);
1408 rcontrol->SetFocusActions(focusActions);
1409 rcontrol->SetUnFocusActions(unfocusActions);
1411 break;
1413 case CGUIControl::GUICONTROL_SPIN:
1415 control = new CGUISpinControl(parentID, id, posX, posY, width, height, textureUp, textureDown,
1416 textureUpFocus, textureDownFocus, textureUpDisabled,
1417 textureDownDisabled, labelInfo, iType);
1419 CGUISpinControl* scontrol = static_cast<CGUISpinControl*>(control);
1420 scontrol->SetReverse(bReverse);
1422 if (iType == SPIN_CONTROL_TYPE_INT)
1424 scontrol->SetRange(iMin, iMax);
1426 else if (iType == SPIN_CONTROL_TYPE_PAGE)
1428 scontrol->SetRange(iMin, iMax);
1429 scontrol->SetShowRange(true);
1430 scontrol->SetReverse(false);
1431 scontrol->SetShowOnePage(showOnePage);
1433 else if (iType == SPIN_CONTROL_TYPE_FLOAT)
1435 scontrol->SetFloatRange(fMin, fMax);
1436 scontrol->SetFloatInterval(fInterval);
1439 break;
1441 case CGUIControl::GUICONTROL_SLIDER:
1443 control = new CGUISliderControl(
1444 parentID, id, posX, posY, width, height, textureBar, textureBarDisabled, textureNib,
1445 textureNibFocus, textureNibDisabled, SLIDER_CONTROL_TYPE_PERCENTAGE, orientation);
1447 static_cast<CGUISliderControl*>(control)->SetInfo(singleInfo);
1448 static_cast<CGUISliderControl*>(control)->SetAction(action);
1450 break;
1452 case CGUIControl::GUICONTROL_SETTINGS_SLIDER:
1454 control = new CGUISettingsSliderControl(
1455 parentID, id, posX, posY, width, height, sliderWidth, sliderHeight, textureFocus,
1456 textureNoFocus, textureBar, textureBarDisabled, textureNib, textureNibFocus,
1457 textureNibDisabled, labelInfo, SLIDER_CONTROL_TYPE_PERCENTAGE);
1459 static_cast<CGUISettingsSliderControl*>(control)->SetText(strLabel);
1460 static_cast<CGUISettingsSliderControl*>(control)->SetInfo(singleInfo);
1462 break;
1464 case CGUIControl::GUICONTROL_SCROLLBAR:
1466 control = new GUIScrollBarControl(parentID, id, posX, posY, width, height, textureBackground,
1467 textureBar, textureBarFocus, textureNib, textureNibFocus,
1468 orientation, showOnePage);
1469 break;
1471 case CGUIControl::GUICONTROL_PROGRESS:
1473 control =
1474 new CGUIProgressControl(parentID, id, posX, posY, width, height, textureBackground,
1475 textureLeft, textureMid, textureRight, textureOverlay, bReveal);
1477 static_cast<CGUIProgressControl*>(control)->SetInfo(singleInfo, singleInfo2);
1479 break;
1481 case CGUIControl::GUICONTROL_RANGES:
1483 control =
1484 new CGUIRangesControl(parentID, id, posX, posY, width, height, textureBackground,
1485 textureLeft, textureMid, textureRight, textureOverlay, singleInfo);
1486 break;
1488 case CGUIControl::GUICONTROL_IMAGE:
1490 // use a bordered texture if we have <bordersize> or <bordertexture> specified.
1491 if (borderTexture.filename.empty() && borderStr.empty())
1492 control = new CGUIImage(parentID, id, posX, posY, width, height, texture);
1493 else
1494 control = new CGUIBorderedImage(parentID, id, posX, posY, width, height, texture,
1495 borderTexture, borderSize);
1496 CGUIImage* icontrol = static_cast<CGUIImage*>(control);
1497 icontrol->SetInfo(textureFile);
1498 icontrol->SetAspectRatio(aspect);
1499 icontrol->SetCrossFade(fadeTime);
1501 break;
1503 case CGUIControl::GUICONTROL_MULTI_IMAGE:
1505 control = new CGUIMultiImage(parentID, id, posX, posY, width, height, texture, timePerImage,
1506 fadeTime, randomized, loop, timeToPauseAtEnd);
1507 static_cast<CGUIMultiImage*>(control)->SetInfo(texturePath);
1508 static_cast<CGUIMultiImage*>(control)->SetAspectRatio(aspect);
1510 break;
1512 case CGUIControl::GUICONTAINER_LIST:
1514 CScroller scroller;
1515 GetScroller(pControlNode, "scrolltime", scroller);
1517 control = new CGUIListContainer(parentID, id, posX, posY, width, height, orientation,
1518 scroller, preloadItems);
1519 CGUIListContainer* lcontrol = static_cast<CGUIListContainer*>(control);
1520 lcontrol->LoadLayout(pControlNode);
1521 lcontrol->LoadListProvider(pControlNode, defaultControl, defaultAlways);
1522 lcontrol->SetType(viewType, viewLabel);
1523 lcontrol->SetPageControl(pageControl);
1524 lcontrol->SetRenderOffset(offset);
1525 lcontrol->SetAutoScrolling(pControlNode);
1526 lcontrol->SetClickActions(clickActions);
1527 lcontrol->SetFocusActions(focusActions);
1528 lcontrol->SetUnFocusActions(unfocusActions);
1530 break;
1532 case CGUIControl::GUICONTAINER_WRAPLIST:
1534 CScroller scroller;
1535 GetScroller(pControlNode, "scrolltime", scroller);
1537 control = new CGUIWrappingListContainer(parentID, id, posX, posY, width, height, orientation,
1538 scroller, preloadItems, focusPosition);
1539 CGUIWrappingListContainer* wcontrol = static_cast<CGUIWrappingListContainer*>(control);
1540 wcontrol->LoadLayout(pControlNode);
1541 wcontrol->LoadListProvider(pControlNode, defaultControl, defaultAlways);
1542 wcontrol->SetType(viewType, viewLabel);
1543 wcontrol->SetPageControl(pageControl);
1544 wcontrol->SetRenderOffset(offset);
1545 wcontrol->SetAutoScrolling(pControlNode);
1546 wcontrol->SetClickActions(clickActions);
1547 wcontrol->SetFocusActions(focusActions);
1548 wcontrol->SetUnFocusActions(unfocusActions);
1550 break;
1552 case CGUIControl::GUICONTAINER_EPGGRID:
1554 CGUIEPGGridContainer* epgGridContainer =
1555 new CGUIEPGGridContainer(parentID, id, posX, posY, width, height, orientation, scrollTime,
1556 preloadItems, timeBlocks, rulerUnit, textureProgressIndicator);
1557 control = epgGridContainer;
1558 epgGridContainer->LoadLayout(pControlNode);
1559 epgGridContainer->SetRenderOffset(offset);
1560 epgGridContainer->SetType(viewType, viewLabel);
1561 epgGridContainer->SetPageControl(pageControl);
1563 break;
1565 case CGUIControl::GUICONTAINER_FIXEDLIST:
1567 CScroller scroller;
1568 GetScroller(pControlNode, "scrolltime", scroller);
1570 control = new CGUIFixedListContainer(parentID, id, posX, posY, width, height, orientation,
1571 scroller, preloadItems, focusPosition, iMovementRange);
1572 CGUIFixedListContainer* fcontrol = static_cast<CGUIFixedListContainer*>(control);
1573 fcontrol->LoadLayout(pControlNode);
1574 fcontrol->LoadListProvider(pControlNode, defaultControl, defaultAlways);
1575 fcontrol->SetType(viewType, viewLabel);
1576 fcontrol->SetPageControl(pageControl);
1577 fcontrol->SetRenderOffset(offset);
1578 fcontrol->SetAutoScrolling(pControlNode);
1579 fcontrol->SetClickActions(clickActions);
1580 fcontrol->SetFocusActions(focusActions);
1581 fcontrol->SetUnFocusActions(unfocusActions);
1583 break;
1585 case CGUIControl::GUICONTAINER_PANEL:
1587 CScroller scroller;
1588 GetScroller(pControlNode, "scrolltime", scroller);
1590 control = new CGUIPanelContainer(parentID, id, posX, posY, width, height, orientation,
1591 scroller, preloadItems);
1592 CGUIPanelContainer* pcontrol = static_cast<CGUIPanelContainer*>(control);
1593 pcontrol->LoadLayout(pControlNode);
1594 pcontrol->LoadListProvider(pControlNode, defaultControl, defaultAlways);
1595 pcontrol->SetType(viewType, viewLabel);
1596 pcontrol->SetPageControl(pageControl);
1597 pcontrol->SetRenderOffset(offset);
1598 pcontrol->SetAutoScrolling(pControlNode);
1599 pcontrol->SetClickActions(clickActions);
1600 pcontrol->SetFocusActions(focusActions);
1601 pcontrol->SetUnFocusActions(unfocusActions);
1603 break;
1605 case CGUIControl::GUICONTROL_TEXTBOX:
1607 if (!strMonoFont.empty())
1609 labelInfoMono = labelInfo;
1610 labelInfoMono.font = g_fontManager.GetFont(strMonoFont);
1612 control = new CGUITextBox(parentID, id, posX, posY, width, height, labelInfo, scrollTime,
1613 strMonoFont.empty() ? nullptr : &labelInfoMono);
1615 CGUITextBox* tcontrol = static_cast<CGUITextBox*>(control);
1617 tcontrol->SetPageControl(pageControl);
1618 if (infoLabels.size())
1619 tcontrol->SetInfo(infoLabels[0]);
1620 tcontrol->SetAutoScrolling(pControlNode);
1621 tcontrol->SetMinHeight(minHeight);
1623 break;
1625 case CGUIControl::GUICONTROL_MOVER:
1627 control = new CGUIMoverControl(parentID, id, posX, posY, width, height, textureFocus,
1628 textureNoFocus, movingSpeedCfg);
1629 break;
1631 case CGUIControl::GUICONTROL_RESIZE:
1633 control = new CGUIResizeControl(parentID, id, posX, posY, width, height, textureFocus,
1634 textureNoFocus, movingSpeedCfg);
1635 break;
1637 case CGUIControl::GUICONTROL_SPINEX:
1639 control = new CGUISpinControlEx(parentID, id, posX, posY, width, height, spinWidth,
1640 spinHeight, labelInfo, textureFocus, textureNoFocus,
1641 textureUp, textureDown, textureUpFocus, textureDownFocus,
1642 textureUpDisabled, textureDownDisabled, labelInfo, iType);
1644 CGUISpinControlEx* scontrol = static_cast<CGUISpinControlEx*>(control);
1645 scontrol->SetSpinPosition(spinPosX);
1646 scontrol->SetText(strLabel);
1647 scontrol->SetReverse(bReverse);
1649 break;
1651 case CGUIControl::GUICONTROL_VISUALISATION:
1653 control = new CGUIVisualisationControl(parentID, id, posX, posY, width, height);
1654 break;
1656 case CGUIControl::GUICONTROL_RENDERADDON:
1658 control = new CGUIRenderingControl(parentID, id, posX, posY, width, height);
1659 break;
1661 case CGUIControl::GUICONTROL_GAMECONTROLLER:
1663 control = new GAME::CGUIGameController(parentID, id, posX, posY, width, height, texture);
1665 GAME::CGUIGameController* gcontrol = static_cast<GAME::CGUIGameController*>(control);
1667 // Set texture
1668 gcontrol->SetInfo(textureFile);
1670 // Set aspect ratio
1671 gcontrol->SetAspectRatio(aspect);
1673 // Set controller ID
1674 GUIINFO::CGUIInfoLabel controllerId;
1675 GetInfoLabel(pControlNode, "controllerid", controllerId, parentID);
1676 gcontrol->SetControllerID(controllerId);
1678 // Set controller address
1679 GUIINFO::CGUIInfoLabel controllerAddress;
1680 GetInfoLabel(pControlNode, "controlleraddress", controllerAddress, parentID);
1681 gcontrol->SetControllerAddress(controllerAddress);
1683 // Set controller diffuse color
1684 GUIINFO::CGUIInfoColor controllerDiffuse(0xFFFFFFFF);
1685 GetInfoColor(pControlNode, "controllerdiffuse", controllerDiffuse, parentID);
1686 gcontrol->SetControllerDiffuse(controllerDiffuse);
1688 // Set port address
1689 GUIINFO::CGUIInfoLabel portAddress;
1690 GetInfoLabel(pControlNode, "portaddress", portAddress, parentID);
1691 gcontrol->SetPortAddress(portAddress);
1693 // Set peripheral location
1694 GUIINFO::CGUIInfoLabel peripheralLocation;
1695 GetInfoLabel(pControlNode, "peripherallocation", peripheralLocation, parentID);
1696 gcontrol->SetPeripheralLocation(peripheralLocation);
1698 break;
1700 case CGUIControl::GUICONTROL_GAMECONTROLLERLIST:
1702 CScroller scroller;
1703 GetScroller(pControlNode, "scrolltime", scroller);
1705 control = new GAME::CGUIGameControllerList(parentID, id, posX, posY, width, height,
1706 orientation, labelInfo.align, scroller);
1708 GAME::CGUIGameControllerList* lcontrol = static_cast<GAME::CGUIGameControllerList*>(control);
1710 lcontrol->LoadLayout(pControlNode);
1711 lcontrol->LoadListProvider(pControlNode, defaultControl, defaultAlways);
1712 lcontrol->SetType(viewType, viewLabel);
1713 lcontrol->SetPageControl(pageControl);
1714 lcontrol->SetRenderOffset(offset);
1715 lcontrol->SetAutoScrolling(pControlNode);
1716 lcontrol->SetClickActions(clickActions);
1717 lcontrol->SetFocusActions(focusActions);
1718 lcontrol->SetUnFocusActions(unfocusActions);
1720 break;
1722 case CGUIControl::GUICONTROL_COLORBUTTON:
1724 control = new CGUIColorButtonControl(parentID, id, posX, posY, width, height, textureFocus,
1725 textureNoFocus, labelInfo, textureColorMask,
1726 textureColorDisabledMask);
1728 CGUIColorButtonControl* rcontrol = static_cast<CGUIColorButtonControl*>(control);
1729 rcontrol->SetLabel(strLabel);
1730 rcontrol->SetImageBoxColor(colorBox);
1731 rcontrol->SetColorDimensions(colorPosX, colorPosY, colorWidth, colorHeight);
1732 rcontrol->SetClickActions(clickActions);
1733 rcontrol->SetFocusActions(focusActions);
1734 rcontrol->SetUnFocusActions(unfocusActions);
1736 break;
1738 default:
1739 break;
1742 // things that apply to all controls
1743 if (control)
1745 control->SetHitRect(hitRect, hitColor);
1746 control->SetVisibleCondition(visibleCondition, allowHiddenFocus);
1747 control->SetEnableCondition(enableCondition);
1748 control->SetAnimations(animations);
1749 control->SetColorDiffuse(colorDiffuse);
1750 control->SetActions(actions);
1751 control->SetPulseOnSelect(bPulse);
1752 if (hasCamera)
1753 control->SetCamera(camera);
1754 control->SetStereoFactor(stereo);
1756 return control;