1 #pragma once 2 #ifndef ES_CORE_THEME_DATA_H 3 #define ES_CORE_THEME_DATA_H 4 5 #include "math/Vector2f.h" 6 #include "math/Vector4f.h" 7 #include "utils/FileSystemUtil.h" 8 #include <deque> 9 #include <map> 10 #include <memory> 11 #include <sstream> 12 #include <vector> 13 14 namespace pugi { class xml_node; } 15 16 template<typename T> 17 class TextListComponent; 18 19 class GuiComponent; 20 class ImageComponent; 21 class NinePatchComponent; 22 class Sound; 23 class TextComponent; 24 class Window; 25 26 namespace ThemeFlags 27 { 28 enum PropertyFlags : unsigned int 29 { 30 PATH = 1, 31 POSITION = 2, 32 SIZE = 4, 33 ORIGIN = 8, 34 COLOR = 16, 35 FONT_PATH = 32, 36 FONT_SIZE = 64, 37 SOUND = 128, 38 ALIGNMENT = 256, 39 TEXT = 512, 40 FORCE_UPPERCASE = 1024, 41 LINE_SPACING = 2048, 42 DELAY = 4096, 43 Z_INDEX = 8192, 44 ROTATION = 16384, 45 VISIBLE = 32768, 46 ALL = 0xFFFFFFFF 47 }; 48 } 49 50 class ThemeException : public std::exception 51 { 52 public: 53 std::string msg; 54 what()55 virtual const char* what() const throw() { return msg.c_str(); } 56 57 template<typename T> 58 friend ThemeException& operator<<(ThemeException& e, T msg); 59 setFiles(const std::deque<std::string> & deque)60 inline void setFiles(const std::deque<std::string>& deque) 61 { 62 *this << "from theme \"" << deque.front() << "\"\n"; 63 for(auto it = deque.cbegin() + 1; it != deque.cend(); it++) 64 *this << " (from included file \"" << (*it) << "\")\n"; 65 *this << " "; 66 } 67 }; 68 69 template<typename T> 70 ThemeException& operator<<(ThemeException& e, T appendMsg) 71 { 72 std::stringstream ss; 73 ss << e.msg << appendMsg; 74 e.msg = ss.str(); 75 return e; 76 } 77 78 struct ThemeSet 79 { 80 std::string path; 81 getNameThemeSet82 inline std::string getName() const { return Utils::FileSystem::getStem(path); } getThemePathThemeSet83 inline std::string getThemePath(const std::string& system) const { return path + "/" + system + "/theme.xml"; } 84 }; 85 86 class ThemeData 87 { 88 public: 89 90 class ThemeElement 91 { 92 public: 93 bool extra; 94 std::string type; 95 96 struct Property 97 { 98 void operator= (const Vector4f& value) { r = value; v = Vector2f(value.x(), value.y()); } 99 void operator= (const Vector2f& value) { v = value; } 100 void operator= (const std::string& value) { s = value; } 101 void operator= (const unsigned int& value) { i = value; } 102 void operator= (const float& value) { f = value; } 103 void operator= (const bool& value) { b = value; } 104 105 Vector4f r; 106 Vector2f v; 107 std::string s; 108 unsigned int i; 109 float f; 110 bool b; 111 }; 112 113 std::map< std::string, Property > properties; 114 115 template<typename T> get(const std::string & prop)116 const T get(const std::string& prop) const 117 { 118 if( std::is_same<T, Vector2f>::value) return *(const T*)&properties.at(prop).v; 119 else if(std::is_same<T, std::string>::value) return *(const T*)&properties.at(prop).s; 120 else if(std::is_same<T, unsigned int>::value) return *(const T*)&properties.at(prop).i; 121 else if(std::is_same<T, float>::value) return *(const T*)&properties.at(prop).f; 122 else if(std::is_same<T, bool>::value) return *(const T*)&properties.at(prop).b; 123 else if(std::is_same<T, Vector4f>::value) return *(const T*)&properties.at(prop).r; 124 return T(); 125 } 126 has(const std::string & prop)127 inline bool has(const std::string& prop) const { return (properties.find(prop) != properties.cend()); } 128 }; 129 130 private: 131 class ThemeView 132 { 133 public: 134 std::map<std::string, ThemeElement> elements; 135 std::vector<std::string> orderedKeys; 136 }; 137 138 public: 139 140 ThemeData(); 141 142 // throws ThemeException 143 void loadFile(std::map<std::string, std::string> sysDataMap, const std::string& path); 144 145 enum ElementPropertyType 146 { 147 NORMALIZED_RECT, 148 NORMALIZED_PAIR, 149 PATH, 150 STRING, 151 COLOR, 152 FLOAT, 153 BOOLEAN 154 }; 155 156 bool hasView(const std::string& view); 157 158 // If expectedType is an empty string, will do no type checking. 159 const ThemeElement* getElement(const std::string& view, const std::string& element, const std::string& expectedType) const; 160 161 static std::vector<GuiComponent*> makeExtras(const std::shared_ptr<ThemeData>& theme, const std::string& view, Window* window); 162 163 static const std::shared_ptr<ThemeData>& getDefault(); 164 165 static std::map<std::string, ThemeSet> getThemeSets(); 166 static std::string getThemeFromCurrentSet(const std::string& system); 167 168 private: 169 static std::map< std::string, std::map<std::string, ElementPropertyType> > sElementMap; 170 static std::vector<std::string> sSupportedFeatures; 171 static std::vector<std::string> sSupportedViews; 172 173 std::deque<std::string> mPaths; 174 float mVersion; 175 176 void parseFeatures(const pugi::xml_node& themeRoot); 177 void parseIncludes(const pugi::xml_node& themeRoot); 178 void parseVariables(const pugi::xml_node& root); 179 void parseViews(const pugi::xml_node& themeRoot); 180 void parseView(const pugi::xml_node& viewNode, ThemeView& view); 181 void parseElement(const pugi::xml_node& elementNode, const std::map<std::string, ElementPropertyType>& typeMap, ThemeElement& element); 182 183 std::map<std::string, ThemeView> mViews; 184 }; 185 186 #endif // ES_CORE_THEME_DATA_H 187