1 // Aseprite Code Generator
2 // Copyright (c) 2015-2017 David Capello
3 //
4 // This file is released under the terms of the MIT license.
5 // Read LICENSE.txt for more information.
6 
7 #include "gen/theme_class.h"
8 
9 #include "base/string.h"
10 #include "gen/common.h"
11 
12 #include <cstring>
13 #include <iostream>
14 #include <vector>
15 
gen_theme_class(TiXmlDocument * doc,const std::string & inputFn)16 void gen_theme_class(TiXmlDocument* doc, const std::string& inputFn)
17 {
18   std::vector<std::string> dimensions;
19   std::vector<std::string> colors;
20   std::vector<std::string> parts;
21   std::vector<std::string> cursors;
22   std::vector<std::string> styles;
23 
24   TiXmlHandle handle(doc);
25   TiXmlElement* elem = handle
26     .FirstChild("theme")
27     .FirstChild("dimensions")
28     .FirstChild("dim").ToElement();
29   while (elem) {
30     const char* id = elem->Attribute("id");
31     dimensions.push_back(id);
32     elem = elem->NextSiblingElement();
33   }
34 
35   elem = handle
36     .FirstChild("theme")
37     .FirstChild("colors")
38     .FirstChild("color").ToElement();
39   while (elem) {
40     const char* id = elem->Attribute("id");
41     colors.push_back(id);
42     elem = elem->NextSiblingElement();
43   }
44 
45   elem = handle
46     .FirstChild("theme")
47     .FirstChild("parts")
48     .FirstChild("part").ToElement();
49   while (elem) {
50     const char* id = elem->Attribute("id");
51     if (std::strncmp(id, "cursor_", 7) == 0) {
52       cursors.push_back(std::string(id).substr(7));
53     }
54     else if (!std::strchr(id, ':'))
55       parts.push_back(id);
56     elem = elem->NextSiblingElement();
57   }
58 
59   elem = handle
60     .FirstChild("theme")
61     .FirstChild("styles")
62     .FirstChild("style").ToElement();
63   while (elem) {
64     const char* id = elem->Attribute("id");
65     styles.push_back(id);
66     elem = elem->NextSiblingElement();
67   }
68 
69   std::cout
70     << "// Don't modify, generated file from " << inputFn << "\n"
71     << "\n"
72     << "#ifndef GENERATED_THEME_H_INCLUDED\n"
73     << "#define GENERATED_THEME_H_INCLUDED\n"
74     << "#pragma once\n"
75     << "\n"
76     << "namespace app {\n"
77     << "namespace gen {\n"
78     << "\n"
79     << "  template<typename T>\n"
80     << "  class ThemeFile {\n"
81     << "  public:\n"
82     << "\n";
83 
84   // Dimensions sub class
85   std::cout
86     << "    class Dimensions {\n"
87     << "      template<typename> friend class ThemeFile;\n"
88     << "    public:\n";
89   for (auto dimension : dimensions) {
90     std::string id = convert_xmlid_to_cppid(dimension, false);
91     std::cout
92       << "      int " << id << "() const { return m_" << id << "; }\n";
93   }
94   std::cout
95     << "    private:\n";
96   for (auto dimension : dimensions) {
97     std::string id = convert_xmlid_to_cppid(dimension, false);
98     std::cout
99       << "      int m_" << id << ";\n";
100   }
101   std::cout
102     << "    };\n";
103 
104   // Colors sub class
105   std::cout
106     << "    class Colors {\n"
107     << "      template<typename> friend class ThemeFile;\n"
108     << "    public:\n";
109   for (auto color : colors) {
110     std::string id = convert_xmlid_to_cppid(color, false);
111     std::cout
112       << "      gfx::Color " << id << "() const { return m_" << id << "; }\n";
113   }
114   std::cout
115     << "    private:\n";
116   for (auto color : colors) {
117     std::string id = convert_xmlid_to_cppid(color, false);
118     std::cout
119       << "      gfx::Color m_" << id << ";\n";
120   }
121   std::cout
122     << "    };\n";
123 
124   // Parts sub class
125   std::cout
126     << "    class Parts {\n"
127     << "      template<typename> friend class ThemeFile;\n"
128     << "    public:\n";
129   for (auto part : parts) {
130     std::string id = convert_xmlid_to_cppid(part, false);
131     std::cout
132       << "      const skin::SkinPartPtr& " << id << "() const { return m_" << id << "; }\n";
133   }
134   std::cout
135     << "    private:\n";
136   for (auto part : parts) {
137     std::string id = convert_xmlid_to_cppid(part, false);
138     std::cout
139       << "      skin::SkinPartPtr m_" << id << ";\n";
140   }
141   std::cout
142     << "    };\n";
143 
144   // Cursors sub class
145   std::cout
146     << "    class Cursors {\n"
147     << "      template<typename> friend class ThemeFile;\n"
148     << "    public:\n";
149   for (auto cursor : cursors) {
150     std::string id = convert_xmlid_to_cppid(cursor, false);
151     std::cout
152       << "      const ui::Cursor* " << id << "() const { return m_" << id << "; }\n";
153   }
154   std::cout
155     << "    private:\n";
156   for (auto cursor : cursors) {
157     std::string id = convert_xmlid_to_cppid(cursor, false);
158     std::cout
159       << "      ui::Cursor* m_" << id << ";\n";
160   }
161   std::cout
162     << "    };\n";
163 
164   // Styles sub class
165   std::cout
166     << "\n"
167     << "    class Styles {\n"
168     << "      template<typename> friend class ThemeFile;\n"
169     << "    public:\n";
170   for (auto style : styles) {
171     std::string id = convert_xmlid_to_cppid(style, false);
172     std::cout
173       << "      ui::Style* " << id << "() const { return m_" << id << "; }\n";
174   }
175   std::cout
176     << "    private:\n";
177   for (auto style : styles) {
178     std::string id = convert_xmlid_to_cppid(style, false);
179     std::cout
180       << "      ui::Style* m_" << id << ";\n";
181   }
182   std::cout
183     << "    };\n";
184 
185   std::cout
186     << "\n"
187     << "    Dimensions dimensions;\n"
188     << "    Colors colors;\n"
189     << "    Parts parts;\n"
190     << "    Cursors cursors;\n"
191     << "    Styles styles;\n"
192     << "\n"
193     << "  protected:\n"
194     << "    void updateInternals() {\n";
195   for (auto dimension : dimensions) {
196     std::string id = convert_xmlid_to_cppid(dimension, false);
197     std::cout << "      byId(dimensions.m_" << id
198               << ", \"" << dimension << "\");\n";
199   }
200   for (auto color : colors) {
201     std::string id = convert_xmlid_to_cppid(color, false);
202     std::cout << "      byId(colors.m_" << id
203               << ", \"" << color << "\");\n";
204   }
205   for (auto part : parts) {
206     std::string id = convert_xmlid_to_cppid(part, false);
207     std::cout << "      byId(parts.m_" << id
208               << ", \"" << part << "\");\n";
209   }
210   for (auto cursor : cursors) {
211     std::string id = convert_xmlid_to_cppid(cursor, false);
212     std::cout << "      byId(cursors.m_" << id
213               << ", \"" << cursor << "\");\n";
214   }
215   for (auto style : styles) {
216     std::string id = convert_xmlid_to_cppid(style, false);
217     std::cout << "      byId(styles.m_" << id
218               << ", \"" << style << "\");\n";
219   }
220   std::cout
221     << "    }\n"
222     << "\n"
223     << "  private:\n"
224     << "    void byId(int& dimension, const std::string& id) {\n"
225     << "      dimension = static_cast<T*>(this)->getDimensionById(id);\n"
226     << "    }\n"
227     << "    void byId(gfx::Color& color, const std::string& id) {\n"
228     << "      color = static_cast<T*>(this)->getColorById(id);\n"
229     << "    }\n"
230     << "    void byId(skin::SkinPartPtr& part, const std::string& id) {\n"
231     << "      part = static_cast<T*>(this)->getPartById(id);\n"
232     << "    }\n"
233     << "    void byId(ui::Cursor*& cursor, const std::string& id) {\n"
234     << "      cursor = static_cast<T*>(this)->getCursorById(id);\n"
235     << "    }\n"
236     << "    void byId(ui::Style*& style, const std::string& id) {\n"
237     << "      style = static_cast<T*>(this)->getStyleById(id);\n"
238     << "    }\n";
239 
240   std::cout
241     << "  };\n"
242     << "\n"
243     << "} // namespace gen\n"
244     << "} // namespace app\n"
245     << "\n"
246     << "#endif\n";
247 }
248