mirror of
				https://github.com/RetroDECK/ES-DE.git
				synced 2025-04-10 19:15:13 +00:00 
			
		
		
		
	Merge pull request #173 from jrassa/theme-variables
variable support for themes
This commit is contained in:
		
						commit
						394cd44758
					
				
							
								
								
									
										41
									
								
								THEMES.md
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								THEMES.md
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -6,7 +6,7 @@ EmulationStation allows each system to have its own "theme." A theme is a collec
 | 
			
		|||
The first place ES will check for a theme is in the system's `<path>` folder, for a theme.xml file:
 | 
			
		||||
* `[SYSTEM_PATH]/theme.xml`
 | 
			
		||||
 | 
			
		||||
If that file doesn't exist, ES will try to find the theme in the current **theme set**.  Theme sets are just a collection of individual system themes arranged in the "themes" folder under some name.  Here's an example:
 | 
			
		||||
If that file doesn't exist, ES will try to find the theme in the current **theme set**.  Theme sets are just a collection of individual system themes arranged in the "themes" folder under some name.  A theme set can provide a default theme that will be used if there is no matching system theme.  Here's an example:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
...
 | 
			
		||||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ If that file doesn't exist, ES will try to find the theme in the current **theme
 | 
			
		|||
         common_resources/
 | 
			
		||||
            scroll_sound.wav
 | 
			
		||||
 | 
			
		||||
         theme.xml (Default theme)
 | 
			
		||||
      another_theme_set/
 | 
			
		||||
         snes/
 | 
			
		||||
            theme.xml
 | 
			
		||||
| 
						 | 
				
			
			@ -308,6 +309,40 @@ You can now change the order in which elements are rendered by setting `zIndex`
 | 
			
		|||
	* `text name="logoText"`
 | 
			
		||||
	* `image name="logo"`
 | 
			
		||||
 | 
			
		||||
### Theme variables
 | 
			
		||||
 | 
			
		||||
Theme variables can be used to simplify theme construction.  There are 2 types of variables available.
 | 
			
		||||
* System Variables
 | 
			
		||||
* Theme Defined Variables
 | 
			
		||||
 | 
			
		||||
#### System Variables
 | 
			
		||||
 | 
			
		||||
System variables are system specific and are derived from the values in es_systems.cfg.
 | 
			
		||||
* `system.name`
 | 
			
		||||
* `system.fullName`
 | 
			
		||||
* `system.theme`
 | 
			
		||||
 | 
			
		||||
#### Theme Defined Variables
 | 
			
		||||
Variables can also be defined in the theme.
 | 
			
		||||
```
 | 
			
		||||
<variables>
 | 
			
		||||
	<themeColor>8b0000</themeColor>
 | 
			
		||||
</variables>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Usage in themes
 | 
			
		||||
Variables can be used to specify the value of a theme property:
 | 
			
		||||
```
 | 
			
		||||
<color>${themeColor}</color>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
or to specify only a portion of the value of a theme property:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
<color>${themeColor}c0</color>
 | 
			
		||||
<path>./art/logo/${system.theme}.svg</path>
 | 
			
		||||
````
 | 
			
		||||
 | 
			
		||||
Reference
 | 
			
		||||
=========
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -444,8 +479,10 @@ Reference
 | 
			
		|||
	- The help system style for this view.
 | 
			
		||||
* `carousel name="systemcarousel"` -ALL
 | 
			
		||||
	- The system logo carousel
 | 
			
		||||
* `image name="logo"` - PATH
 | 
			
		||||
* `image name="logo"` - PATH | COLOR
 | 
			
		||||
	- A logo image, to be displayed in the system logo carousel.
 | 
			
		||||
* `text name="logoText"` - FONT_PATH | COLOR | FORCE_UPPERCASE
 | 
			
		||||
	- A logo text, to be displayed system name in the system logo carousel when no logo is available.
 | 
			
		||||
* `text name="systemInfo"` - ALL
 | 
			
		||||
	- Displays details of the system currently selected in the carousel.
 | 
			
		||||
* You can use extra elements (elements with `extra="true"`) to add your own backgrounds, etc.  They will be displayed behind the carousel, and scroll relative to the carousel.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -411,15 +411,24 @@ std::string SystemData::getThemePath() const
 | 
			
		|||
{
 | 
			
		||||
	// where we check for themes, in order:
 | 
			
		||||
	// 1. [SYSTEM_PATH]/theme.xml
 | 
			
		||||
	// 2. currently selected theme set
 | 
			
		||||
	// 2. system theme from currently selected theme set [CURRENT_THEME_PATH]/[SYSTEM]/theme.xml
 | 
			
		||||
	// 3. default system theme from currently selected theme set [CURRENT_THEME_PATH]/theme.xml
 | 
			
		||||
 | 
			
		||||
	// first, check game folder
 | 
			
		||||
	fs::path localThemePath = mRootFolder->getPath() / "theme.xml";
 | 
			
		||||
	if(fs::exists(localThemePath))
 | 
			
		||||
		return localThemePath.generic_string();
 | 
			
		||||
 | 
			
		||||
	// not in game folder, try theme sets
 | 
			
		||||
	return ThemeData::getThemeFromCurrentSet(mThemeFolder).generic_string();
 | 
			
		||||
	// not in game folder, try system theme in theme sets
 | 
			
		||||
	localThemePath = ThemeData::getThemeFromCurrentSet(mThemeFolder);
 | 
			
		||||
 | 
			
		||||
	if (fs::exists(localThemePath))
 | 
			
		||||
		return localThemePath.generic_string();
 | 
			
		||||
 | 
			
		||||
	// not system theme, try default system theme in theme set
 | 
			
		||||
	localThemePath = localThemePath.parent_path().parent_path() / "theme.xml";
 | 
			
		||||
 | 
			
		||||
	return localThemePath.generic_string();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SystemData::hasGamelist() const
 | 
			
		||||
| 
						 | 
				
			
			@ -448,7 +457,13 @@ void SystemData::loadTheme()
 | 
			
		|||
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		mTheme->loadFile(path);
 | 
			
		||||
		// build map with system variables for theme to use,
 | 
			
		||||
		std::map<std::string, std::string> sysData;
 | 
			
		||||
		sysData.insert(std::pair<std::string, std::string>("system.name", getName()));
 | 
			
		||||
		sysData.insert(std::pair<std::string, std::string>("system.theme", getThemeFolder()));
 | 
			
		||||
		sysData.insert(std::pair<std::string, std::string>("system.fullName", getFullName()));
 | 
			
		||||
		
 | 
			
		||||
		mTheme->loadFile(sysData, path);
 | 
			
		||||
	} catch(ThemeException& e)
 | 
			
		||||
	{
 | 
			
		||||
		LOG(LogError) << e.what();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,21 +43,27 @@ void SystemView::populate()
 | 
			
		|||
		// make logo
 | 
			
		||||
		if(theme->getElement("system", "logo", "image"))
 | 
			
		||||
		{
 | 
			
		||||
			ImageComponent* logo = new ImageComponent(mWindow, false, false);
 | 
			
		||||
			logo->setMaxSize(Eigen::Vector2f(mCarousel.logoSize.x(), mCarousel.logoSize.y()));
 | 
			
		||||
			logo->applyTheme((*it)->getTheme(), "system", "logo", ThemeFlags::PATH);
 | 
			
		||||
			logo->setPosition((mCarousel.logoSize.x() - logo->getSize().x()) / 2,
 | 
			
		||||
				(mCarousel.logoSize.y() - logo->getSize().y()) / 2); // center
 | 
			
		||||
			e.data.logo = std::shared_ptr<GuiComponent>(logo);
 | 
			
		||||
			std::string path = theme->getElement("system", "logo", "image")->get<std::string>("path");
 | 
			
		||||
 | 
			
		||||
			ImageComponent* logoSelected = new ImageComponent(mWindow, false, false);
 | 
			
		||||
			logoSelected->setMaxSize(Eigen::Vector2f(mCarousel.logoSize.x() * mCarousel.logoScale, mCarousel.logoSize.y() * mCarousel.logoScale));
 | 
			
		||||
			logoSelected->applyTheme((*it)->getTheme(), "system", "logo", ThemeFlags::PATH | ThemeFlags::COLOR);
 | 
			
		||||
			logoSelected->setPosition((mCarousel.logoSize.x() - logoSelected->getSize().x()) / 2,
 | 
			
		||||
				(mCarousel.logoSize.y() - logoSelected->getSize().y()) / 2); // center
 | 
			
		||||
			e.data.logoSelected = std::shared_ptr<GuiComponent>(logoSelected);
 | 
			
		||||
			if(!path.empty() && ResourceManager::getInstance()->fileExists(path))
 | 
			
		||||
			{
 | 
			
		||||
				ImageComponent* logo = new ImageComponent(mWindow, false, false);
 | 
			
		||||
				logo->setMaxSize(Eigen::Vector2f(mCarousel.logoSize.x(), mCarousel.logoSize.y()));
 | 
			
		||||
				logo->applyTheme((*it)->getTheme(), "system", "logo", ThemeFlags::PATH | ThemeFlags::COLOR);
 | 
			
		||||
				logo->setPosition((mCarousel.logoSize.x() - logo->getSize().x()) / 2,
 | 
			
		||||
					(mCarousel.logoSize.y() - logo->getSize().y()) / 2); // center
 | 
			
		||||
				e.data.logo = std::shared_ptr<GuiComponent>(logo);
 | 
			
		||||
 | 
			
		||||
		}else{
 | 
			
		||||
				ImageComponent* logoSelected = new ImageComponent(mWindow, false, false);
 | 
			
		||||
				logoSelected->setMaxSize(Eigen::Vector2f(mCarousel.logoSize.x() * mCarousel.logoScale, mCarousel.logoSize.y() * mCarousel.logoScale));
 | 
			
		||||
				logoSelected->applyTheme((*it)->getTheme(), "system", "logo", ThemeFlags::PATH | ThemeFlags::COLOR);
 | 
			
		||||
				logoSelected->setPosition((mCarousel.logoSize.x() - logoSelected->getSize().x()) / 2,
 | 
			
		||||
					(mCarousel.logoSize.y() - logoSelected->getSize().y()) / 2); // center
 | 
			
		||||
				e.data.logoSelected = std::shared_ptr<GuiComponent>(logoSelected);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (!e.data.logo)
 | 
			
		||||
		{
 | 
			
		||||
			// no logo in theme; use text
 | 
			
		||||
			TextComponent* text = new TextComponent(mWindow,
 | 
			
		||||
				(*it)->getName(),
 | 
			
		||||
| 
						 | 
				
			
			@ -65,14 +71,16 @@ void SystemView::populate()
 | 
			
		|||
				0x000000FF,
 | 
			
		||||
				ALIGN_CENTER);
 | 
			
		||||
			text->setSize(mCarousel.logoSize);
 | 
			
		||||
			text->applyTheme((*it)->getTheme(), "system", "logoText", ThemeFlags::FONT_PATH | ThemeFlags::COLOR | ThemeFlags::FORCE_UPPERCASE);
 | 
			
		||||
			e.data.logo = std::shared_ptr<GuiComponent>(text);
 | 
			
		||||
 | 
			
		||||
			TextComponent* textSelected = new TextComponent(mWindow,
 | 
			
		||||
				(*it)->getName(),
 | 
			
		||||
				Font::get((int)(FONT_SIZE_LARGE * 1.5)),
 | 
			
		||||
			TextComponent* textSelected = new TextComponent(mWindow, 
 | 
			
		||||
				(*it)->getName(), 
 | 
			
		||||
				Font::get((int)(FONT_SIZE_LARGE * mCarousel.logoScale)),
 | 
			
		||||
				0x000000FF,
 | 
			
		||||
				ALIGN_CENTER);
 | 
			
		||||
			textSelected->setSize(mCarousel.logoSize);
 | 
			
		||||
			textSelected->applyTheme((*it)->getTheme(), "system", "logoText", ThemeFlags::FONT_PATH | ThemeFlags::COLOR | ThemeFlags::FORCE_UPPERCASE);
 | 
			
		||||
			e.data.logoSelected = std::shared_ptr<GuiComponent>(textSelected);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@
 | 
			
		|||
#include "Settings.h"
 | 
			
		||||
#include "pugixml/src/pugixml.hpp"
 | 
			
		||||
#include <boost/assign.hpp>
 | 
			
		||||
#include <boost/xpressive/xpressive.hpp>
 | 
			
		||||
 | 
			
		||||
#include "components/ImageComponent.h"
 | 
			
		||||
#include "components/TextComponent.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +124,7 @@ std::map< std::string, ElementMapType > ThemeData::sElementMap = boost::assign::
 | 
			
		|||
namespace fs = boost::filesystem;
 | 
			
		||||
 | 
			
		||||
#define MINIMUM_THEME_FORMAT_VERSION 3
 | 
			
		||||
#define CURRENT_THEME_FORMAT_VERSION 4
 | 
			
		||||
#define CURRENT_THEME_FORMAT_VERSION 5
 | 
			
		||||
 | 
			
		||||
// helper
 | 
			
		||||
unsigned int getHexColor(const char* str)
 | 
			
		||||
| 
						 | 
				
			
			@ -170,14 +171,34 @@ std::string resolvePath(const char* in, const fs::path& relative)
 | 
			
		|||
	return path.generic_string();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::map<std::string, std::string> mVariables;
 | 
			
		||||
 | 
			
		||||
std::string &format_variables(const boost::xpressive::smatch &what)
 | 
			
		||||
{
 | 
			
		||||
	return mVariables[what[1].str()];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string resolvePlaceholders(const char* in)
 | 
			
		||||
{
 | 
			
		||||
	if(!in || in[0] == '\0')
 | 
			
		||||
		return std::string(in);
 | 
			
		||||
		
 | 
			
		||||
	std::string inStr(in);
 | 
			
		||||
	
 | 
			
		||||
	using namespace boost::xpressive;
 | 
			
		||||
	sregex rex = "${" >> (s1 = +('.' | _w)) >> '}';
 | 
			
		||||
    
 | 
			
		||||
	std::string output = regex_replace(inStr, rex, format_variables);
 | 
			
		||||
 | 
			
		||||
	return output;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ThemeData::ThemeData()
 | 
			
		||||
{
 | 
			
		||||
	mVersion = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThemeData::loadFile(const std::string& path)
 | 
			
		||||
void ThemeData::loadFile(std::map<std::string, std::string> sysDataMap, const std::string& path)
 | 
			
		||||
{
 | 
			
		||||
	mPaths.push_back(path);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -189,6 +210,9 @@ void ThemeData::loadFile(const std::string& path)
 | 
			
		|||
 | 
			
		||||
	mVersion = 0;
 | 
			
		||||
	mViews.clear();
 | 
			
		||||
	mVariables.clear();
 | 
			
		||||
 | 
			
		||||
	mVariables.insert(sysDataMap.begin(), sysDataMap.end());
 | 
			
		||||
 | 
			
		||||
	pugi::xml_document doc;
 | 
			
		||||
	pugi::xml_parse_result res = doc.load_file(path.c_str());
 | 
			
		||||
| 
						 | 
				
			
			@ -207,12 +231,12 @@ void ThemeData::loadFile(const std::string& path)
 | 
			
		|||
	if(mVersion < MINIMUM_THEME_FORMAT_VERSION)
 | 
			
		||||
		throw error << "Theme uses format version " << mVersion << ". Minimum supported version is " << MINIMUM_THEME_FORMAT_VERSION << ".";
 | 
			
		||||
 | 
			
		||||
	parseVariables(root);
 | 
			
		||||
	parseIncludes(root);
 | 
			
		||||
	parseViews(root);
 | 
			
		||||
	parseFeatures(root);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void ThemeData::parseIncludes(const pugi::xml_node& root)
 | 
			
		||||
{
 | 
			
		||||
	ThemeException error;
 | 
			
		||||
| 
						 | 
				
			
			@ -238,6 +262,7 @@ void ThemeData::parseIncludes(const pugi::xml_node& root)
 | 
			
		|||
		if(!root)
 | 
			
		||||
			throw error << "Missing <theme> tag!";
 | 
			
		||||
 | 
			
		||||
		parseVariables(root);
 | 
			
		||||
		parseIncludes(root);
 | 
			
		||||
		parseViews(root);
 | 
			
		||||
		parseFeatures(root);
 | 
			
		||||
| 
						 | 
				
			
			@ -265,6 +290,26 @@ void ThemeData::parseFeatures(const pugi::xml_node& root)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThemeData::parseVariables(const pugi::xml_node& root)
 | 
			
		||||
{
 | 
			
		||||
	ThemeException error;
 | 
			
		||||
	error.setFiles(mPaths);
 | 
			
		||||
    
 | 
			
		||||
	pugi::xml_node variables = root.child("variables");
 | 
			
		||||
 | 
			
		||||
	if(!variables)
 | 
			
		||||
		return;
 | 
			
		||||
    
 | 
			
		||||
	for(pugi::xml_node_iterator it = variables.begin(); it != variables.end(); ++it)
 | 
			
		||||
	{
 | 
			
		||||
		std::string key = it->name();
 | 
			
		||||
		std::string val = it->text().as_string();
 | 
			
		||||
 | 
			
		||||
		if (!val.empty())
 | 
			
		||||
			mVariables.insert(std::pair<std::string, std::string>(key, val));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThemeData::parseViews(const pugi::xml_node& root)
 | 
			
		||||
{
 | 
			
		||||
	ThemeException error;
 | 
			
		||||
| 
						 | 
				
			
			@ -344,12 +389,12 @@ void ThemeData::parseElement(const pugi::xml_node& root, const std::map<std::str
 | 
			
		|||
		if(typeIt == typeMap.end())
 | 
			
		||||
			throw error << "Unknown property type \"" << node.name() << "\" (for element of type " << root.name() << ").";
 | 
			
		||||
 | 
			
		||||
		std::string str = resolvePlaceholders(node.text().as_string());
 | 
			
		||||
 | 
			
		||||
		switch(typeIt->second)
 | 
			
		||||
		{
 | 
			
		||||
		case NORMALIZED_PAIR:
 | 
			
		||||
		{
 | 
			
		||||
			std::string str = std::string(node.text().as_string());
 | 
			
		||||
 | 
			
		||||
			size_t divider = str.find(' ');
 | 
			
		||||
			if(divider == std::string::npos) 
 | 
			
		||||
				throw error << "invalid normalized pair (property \"" << node.name() << "\", value \"" << str.c_str() << "\")";
 | 
			
		||||
| 
						 | 
				
			
			@ -363,11 +408,11 @@ void ThemeData::parseElement(const pugi::xml_node& root, const std::map<std::str
 | 
			
		|||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		case STRING:
 | 
			
		||||
			element.properties[node.name()] = std::string(node.text().as_string());
 | 
			
		||||
			element.properties[node.name()] = str;
 | 
			
		||||
			break;
 | 
			
		||||
		case PATH:
 | 
			
		||||
		{
 | 
			
		||||
			std::string path = resolvePath(node.text().as_string(), mPaths.back().string());
 | 
			
		||||
			std::string path = resolvePath(str.c_str(), mPaths.back().string());
 | 
			
		||||
			if(!ResourceManager::getInstance()->fileExists(path))
 | 
			
		||||
			{
 | 
			
		||||
				std::stringstream ss;
 | 
			
		||||
| 
						 | 
				
			
			@ -381,14 +426,25 @@ void ThemeData::parseElement(const pugi::xml_node& root, const std::map<std::str
 | 
			
		|||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		case COLOR:
 | 
			
		||||
			element.properties[node.name()] = getHexColor(node.text().as_string());
 | 
			
		||||
			element.properties[node.name()] = getHexColor(str.c_str());
 | 
			
		||||
			break;
 | 
			
		||||
		case FLOAT:
 | 
			
		||||
			element.properties[node.name()] = node.text().as_float();
 | 
			
		||||
		{
 | 
			
		||||
			float floatVal = static_cast<float>(strtod(str.c_str(), 0));
 | 
			
		||||
			element.properties[node.name()] = floatVal;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		case BOOLEAN:
 | 
			
		||||
			element.properties[node.name()] = node.text().as_bool();
 | 
			
		||||
		{
 | 
			
		||||
			// only look at first char
 | 
			
		||||
			char first = str[0];
 | 
			
		||||
			// 1*, t* (true), T* (True), y* (yes), Y* (YES)
 | 
			
		||||
			bool boolVal = (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y');
 | 
			
		||||
 | 
			
		||||
			element.properties[node.name()] = boolVal;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		default:
 | 
			
		||||
			throw error << "Unknown ElementPropertyType for \"" << root.attribute("name").as_string() << "\", property " << node.name();
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -432,7 +488,8 @@ const std::shared_ptr<ThemeData>& ThemeData::getDefault()
 | 
			
		|||
		{
 | 
			
		||||
			try
 | 
			
		||||
			{
 | 
			
		||||
				theme->loadFile(path);
 | 
			
		||||
				std::map<std::string, std::string> emptyMap;
 | 
			
		||||
				theme->loadFile(emptyMap, path);
 | 
			
		||||
			} catch(ThemeException& e)
 | 
			
		||||
			{
 | 
			
		||||
				LOG(LogError) << e.what();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@
 | 
			
		|||
#include <string>
 | 
			
		||||
#include <boost/filesystem.hpp>
 | 
			
		||||
#include <boost/variant.hpp>
 | 
			
		||||
#include <boost/xpressive/xpressive.hpp>
 | 
			
		||||
#include <Eigen/Dense>
 | 
			
		||||
#include "pugixml/src/pugixml.hpp"
 | 
			
		||||
#include "GuiComponent.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +112,7 @@ public:
 | 
			
		|||
	ThemeData();
 | 
			
		||||
 | 
			
		||||
	// throws ThemeException
 | 
			
		||||
	void loadFile(const std::string& path);
 | 
			
		||||
	void loadFile(std::map<std::string, std::string> sysDataMap, const std::string& path);
 | 
			
		||||
 | 
			
		||||
	enum ElementPropertyType
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -145,6 +146,7 @@ private:
 | 
			
		|||
 | 
			
		||||
	void parseFeatures(const pugi::xml_node& themeRoot);
 | 
			
		||||
	void parseIncludes(const pugi::xml_node& themeRoot);
 | 
			
		||||
	void parseVariables(const pugi::xml_node& root);
 | 
			
		||||
	void parseViews(const pugi::xml_node& themeRoot);
 | 
			
		||||
	void parseView(const pugi::xml_node& viewNode, ThemeView& view);
 | 
			
		||||
	void parseElement(const pugi::xml_node& elementNode, const std::map<std::string, ElementPropertyType>& typeMap, ThemeElement& element);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue