GUI: Support styles in xml to reduce xml file size

Also allow sliders to have their own text label instead of
requiring a whole separate text object for the label in the xml.

Change-Id: I6e314efb4bb454d496555ff7e003d743063a1308
diff --git a/gui/pages.cpp b/gui/pages.cpp
index 58e99e6..50c60a6 100644
--- a/gui/pages.cpp
+++ b/gui/pages.cpp
@@ -103,6 +103,56 @@
 }
 
 // Helper APIs
+xml_node<>* FindNode(xml_node<>* parent, const char* nodename, int depth /* = 0 */)
+{
+	xml_node<>* child = parent->first_node(nodename);
+	if (child)
+		return child;
+
+	if (depth == 10) {
+		LOGERR("Too many style loops detected.\n");
+		return NULL;
+	}
+
+	xml_node<>* style = parent->first_node("style");
+	if (style) {
+		while (style) {
+			if (!style->first_attribute("name")) {
+				LOGERR("No name given for style.\n");
+				continue;
+			} else {
+				std::string name = style->first_attribute("name")->value();
+				xml_node<>* node = PageManager::FindStyle(name);
+
+				if (node) {
+					// We found the style that was named
+					xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
+					if (stylenode)
+						return stylenode;
+				}
+			}
+			style = style->next_sibling("style");
+		}
+	} else {
+		// Search for stylename in the parent node <object type="foo" stylename="foo2">
+		xml_attribute<>* attr = parent->first_attribute("style");
+		// If no style is found anywhere else and the node wasn't found in the object itself
+		// as a special case we will search for a style that uses the same style name as the
+		// object type, so <object type="button"> would search for a style named "button"
+		if (!attr)
+			attr = parent->first_attribute("type");
+		if (attr) {
+			xml_node<>* node = PageManager::FindStyle(attr->value());
+			if (node) {
+				xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
+				if (stylenode)
+					return stylenode;
+			}
+		}
+	}
+	return NULL;
+}
+
 std::string LoadAttrString(xml_node<>* element, const char* attrname, const char* defaultvalue)
 {
 	if (!element)
@@ -130,9 +180,10 @@
 	return scale_theme_y(LoadAttrInt(element, attrname, defaultvalue));
 }
 
-COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
+COLOR LoadAttrColor(xml_node<>* element, const char* attrname, bool* found_color, COLOR defaultvalue)
 {
 	string value = LoadAttrString(element, attrname);
+	*found_color = !value.empty();
 	// resolve variables
 	DataManager::GetValue(value, value);
 	COLOR ret = defaultvalue;
@@ -142,6 +193,12 @@
 		return defaultvalue;
 }
 
+COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
+{
+	bool found_color = false;
+	return LoadAttrColor(element, attrname, &found_color, defaultvalue);
+}
+
 FontResource* LoadAttrFont(xml_node<>* element, const char* attrname)
 {
 	std::string name = LoadAttrString(element, attrname, "");
@@ -621,8 +678,7 @@
 	xml_node<>* parent;
 	xml_node<>* child;
 	xml_node<>* xmltemplate;
-	xml_node<>* blank_templates;
-	int pages_loaded = -1, ret;
+	xml_node<>* xmlstyle;
 
 	parent = mDoc.first_node("recovery");
 	if (!parent)
@@ -701,6 +757,11 @@
 	if (xmltemplate)
 		templates.push_back(xmltemplate);
 
+	// Load styles if present
+	xmlstyle = parent->first_node("styles");
+	if (xmlstyle)
+		styles.push_back(xmlstyle);
+
 	child = parent->first_node("pages");
 	if (child) {
 		if (LoadPages(child)) {
@@ -720,6 +781,7 @@
 	xml_node<>* parent;
 	xml_node<>* child;
 	xml_node<>* xmltemplate;
+	xml_node<>* xmlstyle;
 	long len;
 	char* xmlFile = NULL;
 	string filename;
@@ -817,6 +879,11 @@
 		if (xmltemplate)
 			templates.push_back(xmltemplate);
 
+		// Load styles if present
+		xmlstyle = parent->first_node("styles");
+		if (xmlstyle)
+			styles.push_back(xmlstyle);
+
 		child = parent->first_node("pages");
 		if (child && LoadPages(child))
 		{
@@ -1288,6 +1355,23 @@
 	return mHardwareKeyboard;
 }
 
+xml_node<>* PageManager::FindStyle(std::string name)
+{
+	for (std::vector<xml_node<>*>::iterator itr = mCurrentSet->styles.begin(); itr != mCurrentSet->styles.end(); itr++) {
+		xml_node<>* node = (*itr)->first_node("style");
+
+		while (node) {
+			if (!node->first_attribute("name"))
+				continue;
+
+			if (name == node->first_attribute("name")->value())
+				return node;
+			node = node->next_sibling("style");
+		}
+	}
+	return NULL;
+}
+
 MouseCursor *PageManager::GetMouseCursor()
 {
 	if(!mMouseCursor)