diff --git a/assets/games/tictactoe/test.xml b/assets/games/tictactoe/test.xml
new file mode 100644
index 00000000..e34d4901
--- /dev/null
+++ b/assets/games/tictactoe/test.xml
@@ -0,0 +1,5 @@
+
+
+
\ No newline at end of file
diff --git a/src/dawn/asset/Asset.hpp b/src/dawn/asset/Asset.hpp
index 7111d09d..87047d80 100644
--- a/src/dawn/asset/Asset.hpp
+++ b/src/dawn/asset/Asset.hpp
@@ -4,7 +4,7 @@
// https://opensource.org/licenses/MIT
#pragma once
-#include "state/State.hpp"
+#include "state/StateEvent.hpp"
namespace Dawn {
class AssetManager;
diff --git a/src/dawn/display/animation/Animation.hpp b/src/dawn/display/animation/Animation.hpp
index 416dc48e..048be736 100644
--- a/src/dawn/display/animation/Animation.hpp
+++ b/src/dawn/display/animation/Animation.hpp
@@ -4,7 +4,7 @@
// https://opensource.org/licenses/MIT
#pragma once
-#include "state/State.hpp"
+#include "state/StateEvent.hpp"
#include "Easing.hpp"
#include "util/mathutils.hpp"
diff --git a/src/dawn/locale/LocaleManager.hpp b/src/dawn/locale/LocaleManager.hpp
index e341fe16..f6523604 100644
--- a/src/dawn/locale/LocaleManager.hpp
+++ b/src/dawn/locale/LocaleManager.hpp
@@ -1,68 +1,68 @@
-// Copyright (c) 2022 Dominic Masters
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-
-#pragma once
-#include "state/State.hpp"
-#include "asset/AssetManager.hpp"
-
-namespace Dawn {
- class DawnGame;
-
- struct Locale {
- std::string language;
- };
-
- class LocaleManager : public StateOwner {
- private:
- DawnGame *game;
- LanguageAsset *asset;
- struct Locale locale;
- LanguageAsset *currentlyLoadedAsset = nullptr;
- LanguageAsset *loadingAsset = nullptr;
-
- /** Listens for when the pending language loads. */
- void onLanguageLoaded();
-
- public:
- StateEvent<> eventLocaleChanged;
- StateEvent<> eventLanguageUpdated;
-
- /**
- * Initializes the Locale Manager Instance. Locale Manager is responsible
- * for handling anything that will change depending on which region the
- * player is in.
- *
- * @param game Game instance this manager belongs to.
- */
- LocaleManager(DawnGame *game);
-
- /**
- * Initializes the LocaleManager and loads the default language.
- */
- void init();
-
- /**
- * Change the locale and begin loading the new language.
- *
- * @param locale Locale to switch to.
- */
- void setLocale(struct Locale locale);
-
- /**
- * Gets the current locale.
- *
- * @return Current locale.
- */
- struct Locale getLocale();
-
- /**
- * Returns a language string from the language CSV file.
- *
- * @param key Key of the string to get.
- * @return The translated string.
- */
- std::string getString(std::string key);
- };
+// Copyright (c) 2022 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "state/StateEvent.hpp"
+#include "asset/AssetManager.hpp"
+
+namespace Dawn {
+ class DawnGame;
+
+ struct Locale {
+ std::string language;
+ };
+
+ class LocaleManager {
+ private:
+ DawnGame *game;
+ LanguageAsset *asset;
+ struct Locale locale;
+ LanguageAsset *currentlyLoadedAsset = nullptr;
+ LanguageAsset *loadingAsset = nullptr;
+
+ /** Listens for when the pending language loads. */
+ void onLanguageLoaded();
+
+ public:
+ StateEvent<> eventLocaleChanged;
+ StateEvent<> eventLanguageUpdated;
+
+ /**
+ * Initializes the Locale Manager Instance. Locale Manager is responsible
+ * for handling anything that will change depending on which region the
+ * player is in.
+ *
+ * @param game Game instance this manager belongs to.
+ */
+ LocaleManager(DawnGame *game);
+
+ /**
+ * Initializes the LocaleManager and loads the default language.
+ */
+ void init();
+
+ /**
+ * Change the locale and begin loading the new language.
+ *
+ * @param locale Locale to switch to.
+ */
+ void setLocale(struct Locale locale);
+
+ /**
+ * Gets the current locale.
+ *
+ * @return Current locale.
+ */
+ struct Locale getLocale();
+
+ /**
+ * Returns a language string from the language CSV file.
+ *
+ * @param key Key of the string to get.
+ * @return The translated string.
+ */
+ std::string getString(std::string key);
+ };
}
\ No newline at end of file
diff --git a/src/dawn/scene/Scene.hpp b/src/dawn/scene/Scene.hpp
index 3d8913aa..ea8d9d65 100644
--- a/src/dawn/scene/Scene.hpp
+++ b/src/dawn/scene/Scene.hpp
@@ -8,7 +8,7 @@
#include "asset/Asset.hpp"
#include "scene/debug/SceneDebugLine.hpp"
#include "physics/ScenePhysicsManager.hpp"
-#include "state/State.hpp"
+#include "state/StateEvent.hpp"
namespace Dawn {
class DawnGame;
diff --git a/src/dawn/state/StateProvider.hpp b/src/dawn/state/StateProvider.hpp
new file mode 100644
index 00000000..6508dc2b
--- /dev/null
+++ b/src/dawn/state/StateProvider.hpp
@@ -0,0 +1,53 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "state/State.hpp"
+
+namespace Dawn {
+ class SceneItemComponent;
+
+ template
+ struct StateListener {
+ std::function callback;
+ D data;
+ };
+
+ template
+ struct StateProviderSet {
+ private:
+ std::vector> listeners;
+
+ public:
+ std::function addEffect(
+ std::function callback,
+ D data
+ ) {
+ struct StateListener l;
+ l.callback = callback;
+ l.data = data;
+ this->listeners.push_back(l);
+
+ l.callback();
+
+ return std::bind([&](struct StateListener listener) {
+ assertUnreachable();
+ }, l);
+ }
+ };
+
+ class TimeProvider {
+ public:
+ StateProviderSet effect;
+ };
+
+ std::function useTimeout(
+ std::function someCallback,
+ float_t timeout,
+ SceneItemComponent *context
+ ) {
+ return (TimeProvider()).effect.addEffect(someCallback, timeout);
+ }
+}
\ No newline at end of file
diff --git a/src/dawntictactoe/CMakeLists.txt b/src/dawntictactoe/CMakeLists.txt
index ec04854e..1635654a 100644
--- a/src/dawntictactoe/CMakeLists.txt
+++ b/src/dawntictactoe/CMakeLists.txt
@@ -26,3 +26,4 @@ set(DIR_GAME_ASSETS games/tictactoe)
tool_language(locale_en ${DIR_GAME_ASSETS}/locale/en.xml)
tool_tileset(tileset_xo texture_xo ${DIR_GAME_ASSETS}/xo.png 1 4)
tool_truetype(truetype_bizudp ${DIR_GAME_ASSETS}/font/BIZUDPGothic-Bold.ttf truetype_bizudp 2048 2048 120)
+tool_ui(ui_test ${DIR_GAME_ASSETS}/test.xml ui_test)
\ No newline at end of file
diff --git a/src/dawntictactoe/components/TicTacToeGame.cpp b/src/dawntictactoe/components/TicTacToeGame.cpp
index 1da6e217..7bc111a0 100644
--- a/src/dawntictactoe/components/TicTacToeGame.cpp
+++ b/src/dawntictactoe/components/TicTacToeGame.cpp
@@ -7,6 +7,7 @@
#include "game/DawnGame.hpp"
#include "scene/components/example/ExampleSpin.hpp"
#include "scene/components/physics/3d/CubeCollider.hpp"
+#include "state/StateProvider.hpp"
using namespace Dawn;
@@ -29,6 +30,10 @@ void TicTacToeGame::onStart() {
++itTiles;
}
+ useTimeout([&]{
+ std::cout << "Timeout" << std::endl;
+ }, 1000, this)();
+
useEffect([&]{
if(!gameOver) return;
diff --git a/src/dawntictactoe/scenes/TicTacToeScene.hpp b/src/dawntictactoe/scenes/TicTacToeScene.hpp
index e1331b71..cb79f8bb 100644
--- a/src/dawntictactoe/scenes/TicTacToeScene.hpp
+++ b/src/dawntictactoe/scenes/TicTacToeScene.hpp
@@ -12,10 +12,8 @@
#include "prefabs/SimpleLabel.hpp"
#include "scene/components/ui/menu/UISimpleMenu.hpp"
-#include "state/State.hpp"
-
namespace Dawn {
- class TicTacToeScene : public Scene, public StateOwner {
+ class TicTacToeScene : public Scene {
protected:
Camera *camera;
std::function evtUnsub;
diff --git a/src/dawntools/tools/CMakeLists.txt b/src/dawntools/tools/CMakeLists.txt
index 8d671409..d862041a 100644
--- a/src/dawntools/tools/CMakeLists.txt
+++ b/src/dawntools/tools/CMakeLists.txt
@@ -50,8 +50,8 @@ endfunction()
# UI Tool
function(tool_ui target in)
add_custom_target(${target}
- COMMAND uigen "${DAWN_ASSETS_SOURCE_DIR}/${in}" "${DAWN_GENERATED_DIR}/ui/${target}"
- COMMENT "Generating ui ${target} from ${in}"
+ COMMAND uigen --input="${DAWN_ASSETS_SOURCE_DIR}/${in}" --output="${DAWN_GENERATED_DIR}/prefabs/ui/${target}"
+ COMMENT "Generating UI ${target} from ${in}"
DEPENDS uigen
)
target_include_directories(${DAWN_TARGET_NAME}
diff --git a/src/dawntools/tools/uigen/CMakeLists.txt b/src/dawntools/tools/uigen/CMakeLists.txt
index 3fcd0242..535d254b 100644
--- a/src/dawntools/tools/uigen/CMakeLists.txt
+++ b/src/dawntools/tools/uigen/CMakeLists.txt
@@ -3,21 +3,35 @@
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
-# Texture Build Tool
project(uigen VERSION 1.0)
add_executable(uigen)
+
+
+# Sources
target_sources(uigen
PRIVATE
- main.cpp
- ../../util/file.cpp
- ../../util/xml.cpp
+ ${DAWN_SHARED_SOURCES}
+ ${DAWN_TOOL_SOURCES}
+ UIGen.cpp
)
+
+# Includes
target_include_directories(uigen
PUBLIC
${DAWN_SHARED_INCLUDES}
- ${CMAKE_CURRENT_LIST_DIR}/../../
+ ${DAWN_TOOL_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}
)
+
+# Definitions
+target_compile_definitions(uigen
+ PUBLIC
+ ${DAWN_SHARED_DEFINITIONS}
+ DAWN_TOOL_INSTANCE=UIGen
+ DAWN_TOOL_HEADER="UIGen.hpp"
+)
+
+# Libraries
target_link_libraries(uigen
PUBLIC
${DAWN_BUILD_HOST_LIBS}
diff --git a/src/dawntools/tools/uigen/UIGen.cpp b/src/dawntools/tools/uigen/UIGen.cpp
new file mode 100644
index 00000000..989e9c31
--- /dev/null
+++ b/src/dawntools/tools/uigen/UIGen.cpp
@@ -0,0 +1,57 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#include "UIGen.hpp"
+
+using namespace Dawn;
+
+std::vector UIGen::getRequiredFlags() {
+ return std::vector{ "input", "output" };
+}
+
+int32_t UIGen::start() {
+ // Open input file.
+ File file(flags["input"]);
+ std::string buffer;
+ if(!file.readString(&buffer)) {
+ std::cout << "Failed to read " << file.filename << std::endl;
+ return 1;
+ }
+
+ // Parse XML
+ Xml xml = Xml::load(buffer);
+
+ std::string error;
+ struct RootInformation info;
+ auto ret = (RootParser()).parse(&xml, &info, &error);
+ if(ret != 0) {
+ std::cout << error << std::endl;
+ return ret;
+ }
+
+ // std::vector lines;
+ // RootGen::generate(&lines, &info, "");
+
+ // // Generate buffer
+ // std::string bufferOut;
+ // auto itLine = lines.begin();
+ // while(itLine != lines.end()) {
+ // bufferOut += *itLine + "\n";
+ // ++itLine;
+ // }
+
+ // // Finished with XML data, now we can write data out.
+ File fileOut(flags["output"] + ".hpp");
+ if(!fileOut.mkdirp()) {
+ std::cout << "Failed to make ui output dir" << std::endl;
+ return 1;
+ }
+ // if(!fileOut.writeString(bufferOut)) {
+ // std::cout << "Failed to generate scene " << fileOut.filename << std::endl;
+ // return 1;
+ // }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/src/dawntools/tools/uigen/UIGen.hpp b/src/dawntools/tools/uigen/UIGen.hpp
new file mode 100644
index 00000000..4a1da836
--- /dev/null
+++ b/src/dawntools/tools/uigen/UIGen.hpp
@@ -0,0 +1,20 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "util/DawnTool.hpp"
+#include "util/File.hpp"
+#include "parse/root.hpp"
+#include "util/Language.cpp"
+
+namespace Dawn {
+ class UIGen : public DawnTool {
+ protected:
+ std::vector getRequiredFlags() override;
+
+ public:
+ int32_t start();
+ };
+}
\ No newline at end of file
diff --git a/src/dawntools/tools/uigen/main.cpp b/src/dawntools/tools/uigen/main.cpp
deleted file mode 100644
index d49e783a..00000000
--- a/src/dawntools/tools/uigen/main.cpp
+++ /dev/null
@@ -1,343 +0,0 @@
-/**
- * Copyright (c) 2023 Dominic Masters
- *
- * This software is released under the MIT License.
- * https://opensource.org/licenses/MIT
- */
-
-#include "../../util/xml.hpp"
-#include "../../util/file.hpp"
-#include
-#include
-
-struct UIGenerated {
- bool align = false;
- bool alignGrid = false;
- std::string alignX;
- std::string alignY;
- std::string align0;
- std::string align1;
- std::string align2;
- std::string align3;
-
- bool isGrid = false;
- std::string rows;
- std::string columns;
- std::string gutterX;
- std::string gutterY;
-
-
- std::string type;
- std::string name;
-
- std::string parent;
-
- // Optionals
- bool hasColor = false;
- std::string color;
-};
-
-std::vector split(std::string s, std::string delimiter) {
- size_t pos_start = 0, pos_end, delim_len = delimiter.length();
- std::string token;
- std::vector res;
-
- while ((pos_end = s.find (delimiter, pos_start)) != std::string::npos) {
- token = s.substr (pos_start, pos_end - pos_start);
- pos_start = pos_end + delim_len;
- res.push_back(token);
- }
-
- res.push_back (s.substr (pos_start));
- return res;
-}
-
-std::string alignmentFromRaw(std::string strRaw) {
- if(strRaw == "start") return "UI_COMPONENT_ALIGN_START";
- if(strRaw == "middle") return "UI_COMPONENT_ALIGN_MIDDLE";
- if(strRaw == "end") return "UI_COMPONENT_ALIGN_END";
- if(strRaw == "stretch") return "UI_COMPONENT_ALIGN_STRETCH";
- return "";
-}
-
-static bool parseChildren(
- xml_t *currentNode,
- std::string parent,
- std::vector *items
-) {
- // Confirm attributes
- auto attrName = xmlGetAttributeByName(currentNode, "name");
- if(attrName == -1) {
- std::cout << "Missing name attribute." << std::endl;
- return false;
- }
-
- struct UIGenerated item;
- item.name = std::string(currentNode->attributeDatas[attrName] );
- item.type = std::string(currentNode->node);
- item.parent = parent;
-
- // Standard Align
- auto attrAlign = xmlGetAttributeByName(currentNode, "align");
- if(attrAlign != -1) {
- // Parse alignment
- std::string alignRaw(currentNode->attributeDatas[attrAlign]);
- std::vector alignmentParts = split(alignRaw, " ");
- if(alignmentParts.size() != 6) {
- std::cout << "Alignment is invalid" << std::endl;
- return false;
- }
-
- item.align = true;
- item.alignX = alignmentFromRaw(alignmentParts[0]);
- item.alignY = alignmentFromRaw(alignmentParts[1]);
- item.align0 = alignmentParts[2];
- item.align1 = alignmentParts[3];
- item.align2 = alignmentParts[4];
- item.align3 = alignmentParts[5];
-
- if(item.alignX.size() == 0) {
- std::cout << "X Align is invalid" << std::endl;
- return "";
- }
- if(item.alignY.size() == 0) {
- std::cout << "Y Align is invalid" << std::endl;
- return "";
- }
- }
-
- // Grid Align
- auto attrGridAlign = xmlGetAttributeByName(currentNode, "grid");
- if(attrGridAlign != -1) {
- // Parse alignment
- std::string alignRaw(currentNode->attributeDatas[attrGridAlign]);
- std::vector alignmentParts = split(alignRaw, " ");
- if(alignmentParts.size() != 4) {
- std::cout << "Grid alignment is invalid" << std::endl;
- return false;
- }
-
- item.alignGrid = true;
- item.alignX = alignmentFromRaw(alignmentParts[0]);
- item.alignY = alignmentFromRaw(alignmentParts[1]);
- item.align0 = alignmentParts[2];
- item.align1 = alignmentParts[3];
-
- if(item.alignX.size() == 0) {
- std::cout << "X Align is invalid" << std::endl;
- return "";
- }
- if(item.alignY.size() == 0) {
- std::cout << "Y Align is invalid" << std::endl;
- return "";
- }
- }
-
- // Parse color
- auto attrColor = xmlGetAttributeByName(currentNode, "color");
- if(attrColor != -1) {
- item.hasColor = true;
- item.color = currentNode->attributeDatas[attrColor];
- }
-
-
- // Grid
- if(item.type == "UIGrid") {
- auto attrRows = xmlGetAttributeByName(currentNode, "rows");
- auto attrCols = xmlGetAttributeByName(currentNode, "columns");
- auto attrGutter = xmlGetAttributeByName(currentNode, "gutter");
- if(attrRows == -1 || attrCols == -1) {
- std::cout << "Grid is invalid" << std::endl;
- return false;
- }
- item.isGrid = true;
- item.rows = currentNode->attributeDatas[attrRows];
- item.columns = currentNode->attributeDatas[attrCols];
- if(attrGutter != -1) {
- auto gutterParts = split(currentNode->attributeDatas[attrGutter], " ");
- if(gutterParts.size() != 2) {
- std::cout << "Gutter is invalid" << std::endl;
- return false;
- }
- item.gutterX = gutterParts[0];
- item.gutterY = gutterParts[1];
- } else {
- item.gutterX = "0";
- item.gutterY = "0";
- }
- }
-
- // Self
- items->push_back(item);
-
- // Children
- for(int32_t i = 0; i < currentNode->childrenCount; i++) {
- if(!parseChildren(currentNode->children + i, item.name, items)) return false;
- }
-
- return true;
-}
-
-int main(int argc, char *args[]) {
- if(argc != 3) {
- std::cout << "Invalid number of args for ui gen" << std::endl;
- return 1;
- }
-
- // Open input file.
- char fileIn[FILENAME_MAX];
- fileNormalizeSlashes(args[1]);
- sprintf(fileIn, "%s", args[1]);
- FILE *fin = fopen(fileIn, "rb");
- if(fin == NULL) {
- std::cout << "Failed to open input file " << fileIn << std::endl;
- return 1;
- }
-
- // Tell file len
- fseek(fin, 0, SEEK_END);
- auto len = ftell(fin);
- fseek(fin, 0, SEEK_SET);
-
- // Read data.
- char *buffer = (char *)malloc(sizeof(char) * (len + 1));
- if(buffer == NULL) {
- std::cout << "Failed to create temporary memory." << std::endl;
- fclose(fin);
- return 1;
- }
- assetReadString(fin, buffer);
- fclose(fin);
-
- // Parse XML
- xml_t xml;
- xmlLoad(&xml, buffer);
- free(buffer);
-
- // Begin output
- std::string bufferOut = "";
-
- // Imports
- bufferOut += "#pragma once\n";
- for(int32_t i = 0; i < xml.attributeCount; i++) {
- std::string attrName = xml.attributeNames[i];
-
- if(
- attrName == "name"
- ) continue;
-
- bufferOut += "#include \"";
- bufferOut += xml.attributeDatas[i];
- bufferOut += "\"\n";
- }
- bufferOut += "\n";
-
- // Now prep class itself.
- auto attrName = xmlGetAttributeByName(&xml, "name");
- if(attrName == -1) {
- std::cout << "Missing " << std::endl;
- xmlDispose(&xml);
- return 1;
- }
- std::string name = xml.attributeDatas[attrName];
-
- // Children
- std::vector items;
- for(int32_t j = 0; j < xml.childrenCount; j++) {
- if(parseChildren(xml.children + j, "", &items)) continue;
- xmlDispose(&xml);
- return 1;
- }
-
- // Generate strings.
- bufferOut += "namespace Dawn {\n";
- bufferOut += " class " + name + " : public UIEmpty {\n";
- bufferOut += " public:\n";
- auto it = items.begin();
- while(it != items.end()) {
- auto c = *it;
- bufferOut += " " + c.type + " " + c.name + ";\n";
- ++it;
- }
- bufferOut += "\n";
- bufferOut += " " + name + "(UICanvas *canvas) : UIEmpty(canvas),\n";
- it = items.begin();
- while(it != items.end()) {
- auto c = *it;
- bufferOut += " " + c.name + "(canvas)";
- if(it != items.end() - 1) bufferOut += ",";
- bufferOut += "\n";
- ++it;
- }
- bufferOut += " {\n";
-
- it = items.begin();
- while(it != items.end()) {
- auto c = *it;
- bufferOut += "\n";
-
- // Transform
- if(c.align) {
- bufferOut += " " + c.name + ".setTransform(\n";
- bufferOut += " " + c.alignX + ", " + c.alignY + ",\n";
- bufferOut += " glm::vec4(" + c.align0 + ", " + c.align1 + ", " + c.align2 + ", " + c.align3 + "),\n";
- bufferOut += " 0.0f\n";
- bufferOut += " );\n";
- }
-
- // Color
- if(c.hasColor) {
- bufferOut += " " + c.name + ".color = " + c.color + ";\n";
- }
-
- // Grid
- if(c.isGrid) {
- bufferOut += " " + c.name + ".setGridSize(\n";
- bufferOut += " " + c.rows + ", " + c.columns + ",\n";
- bufferOut += " " + c.gutterX + ", " + c.gutterY + "\n";
- bufferOut += " );\n";
- }
-
- // Parent setting
- if(c.alignGrid) {
- bufferOut += " " + c.parent + ".addToGrid(\n";
- bufferOut += " &" + c.name + ",\n";
- bufferOut += " " + c.align0 + ", " + c.align1 + ",\n";
- bufferOut += " " + c.alignX + ", " + c.alignY + "\n";
- bufferOut += " );\n";
- } else {
- if(c.parent == "") {
- bufferOut += " this->addChild(&" + c.name + ");\n";
- } else {
- bufferOut += " " + c.parent + ".addChild(&" + c.name + ");\n";
- }
- }
- ++it;
- }
-
- bufferOut += " }\n";
- bufferOut += " };\n";
- bufferOut += "}";
-
- xmlDispose(&xml);
-
- // Finished with XML data, now we can write data out.
- char fileOut[FILENAME_MAX];
- fileNormalizeSlashes(args[2]);
- sprintf(fileOut, "%s.hpp", args[2]);
- fileMkdirp(fileOut);
- FILE *fout = fopen(fileOut, "wb");
- if(fout == NULL) {
- std::cout << "Failed to open output file." << std::endl;
- return 1;
- }
-
- // Buffer out data.
- const char *bufferOutStr = bufferOut.c_str();
- fwrite(bufferOutStr, sizeof(char), strlen(bufferOutStr), fout);
- fclose(fout);
- std::cout << "Generated UI " << fileOut << std::endl;
-
- // Cleanup
- return 0;
-}
\ No newline at end of file
diff --git a/src/dawntools/tools/uigen/parse/elements/children.hpp b/src/dawntools/tools/uigen/parse/elements/children.hpp
new file mode 100644
index 00000000..4bfe42ba
--- /dev/null
+++ b/src/dawntools/tools/uigen/parse/elements/children.hpp
@@ -0,0 +1,68 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "label.hpp"
+
+namespace Dawn {
+ enum ChildType {
+ CHILD_TYPE_LABEL
+ };
+
+ struct ChildInfo;
+
+ struct ChildrenInfo {
+ std::vector children;
+ };
+
+ struct ChildInfo {
+ enum ChildType type;
+ struct LabelInfo label;
+ struct ChildrenInfo children;
+ };
+
+ class ChildrenParser : public XmlParser {
+ protected:
+ std::vector getRequiredAttributes() {
+ return std::vector();
+ }
+
+ std::map getOptionalAttributes() {
+ return std::map();
+ }
+
+ int32_t onParse(
+ Xml *node,
+ std::map values,
+ struct ChildrenInfo *out,
+ std::string *error
+ ) {
+ // Parse children of self.
+ int32_t ret = 0;
+ auto itChildren = node->children.begin();
+ while(itChildren != node->children.end()) {
+ auto c = *itChildren;
+ struct ChildInfo child;
+
+ if(c->node == "label") {
+ child.type = CHILD_TYPE_LABEL;
+ ret = (LabelParser()).parse(c, &child.label, error);
+ } else {
+ *error = "Unrecognized UI Element " + c->node;
+ return 1;
+ }
+ if(ret != 0) return ret;
+
+ // Now Parse children of children
+ ret = (ChildrenParser()).parse(c, &child.children, error);
+ if(ret != 0) return ret;
+
+ ++itChildren;
+ }
+
+ return ret;
+ }
+ };
+}
\ No newline at end of file
diff --git a/src/dawntools/tools/uigen/parse/elements/label.hpp b/src/dawntools/tools/uigen/parse/elements/label.hpp
new file mode 100644
index 00000000..f82e0f31
--- /dev/null
+++ b/src/dawntools/tools/uigen/parse/elements/label.hpp
@@ -0,0 +1,46 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "util/XmlParser.hpp"
+
+namespace Dawn {
+ struct LabelInfo {
+ std::string text = "";
+ std::string fontSize = "";
+ };
+
+ class LabelParser : public XmlParser {
+ protected:
+ std::vector getRequiredAttributes() {
+ return std::vector();
+ }
+
+ std::map getOptionalAttributes() {
+ return {
+ { "fontSize", "" }
+ };
+ }
+
+ int32_t onParse(
+ Xml *node,
+ std::map values,
+ struct LabelInfo *out,
+ std::string *error
+ ) {
+ int32_t ret = 0;
+
+ if(values["fontSize"].size() > 0) {
+ out->fontSize = values["fontSize"];
+ }
+
+ if(node->value.size() > 0) {
+ out->text = node->value;
+ }
+
+ return ret;
+ }
+ };
+}
\ No newline at end of file
diff --git a/src/dawntools/tools/uigen/parse/root.hpp b/src/dawntools/tools/uigen/parse/root.hpp
new file mode 100644
index 00000000..35701c72
--- /dev/null
+++ b/src/dawntools/tools/uigen/parse/root.hpp
@@ -0,0 +1,106 @@
+// Copyright (c) 2023 Dominic Masters
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "parse/elements/children.hpp"
+
+namespace Dawn {
+ struct RootInformation {
+ std::vector includes;
+ struct ChildrenInfo children;
+ };
+
+ class RootParser : public XmlParser {
+ protected:
+ std::vector getRequiredAttributes() {
+ return std::vector();
+ }
+
+ std::map getOptionalAttributes() {
+ return std::map();
+ }
+
+ int32_t onParse(
+ Xml *node,
+ std::map values,
+ struct RootInformation *out,
+ std::string *error
+ ) {
+ int32_t ret;
+ if(node->node != "root") {
+ *error = "Root node is of an invalid type";
+ return 1;
+ }
+
+ ret = (ChildrenParser()).parse(node, &out->children, error);
+ if(ret != 0) return ret;
+
+ return ret;
+ }
+ };
+
+ // class RootGen : public CodeGen {
+ // public:
+ // static void generate(
+ // std::vector *out,
+ // struct RootInformation *info,
+ // std::string tabs = ""
+ // ) {
+ // struct ClassGenInfo c;
+ // c.clazz = info->header.scene.name;
+ // c.extend = info->header.scene.type;
+ // c.constructorArgs = "DawnGame *game";
+ // c.extendArgs = "game";
+
+ // struct MethodGenInfo vnStage;
+ // vnStage.name = "vnStage";
+ // vnStage.type = "void";
+ // vnStage.isOverride = true;
+ // line(&vnStage.body, info->header.scene.type+ "::vnStage();", "");
+
+ // struct MethodGenInfo getAssets;
+ // getAssets.name = "getRequiredAssets";
+ // getAssets.type = "std::vector";
+ // getAssets.isOverride = true;
+ // line(&getAssets.body, "auto man = &this->game->assetManager;", "");
+ // line(&getAssets.body, "auto assets = " + info->header.scene.type + "::getRequiredAssets();", "");
+
+ // struct MethodGenInfo getVNEvent;
+ // getVNEvent.name = "getVNEvent";
+ // getVNEvent.type = "IVisualNovelEvent *";
+ // getVNEvent.isOverride = true;
+ // line(&getVNEvent.body, "auto start = new VisualNovelEmptyEvent(vnManager);", "");
+
+ // IncludeGen::generate(&c.includes, info->header.includes, "");
+ // IncludeGen::generate(&c.includes, info->events.includes, "");
+
+ // // Characters
+ // auto itChar = info->header.characters.begin();
+ // while(itChar != info->header.characters.end()) {
+ // CharacterGen::generateProperty(&c.publicProperties, *itChar, "");
+ // CharacterGen::generateInitializer(&vnStage.body, *itChar, "");
+ // CharacterGen::generateAssets(&getAssets.body, *itChar, "");
+ // ++itChar;
+ // }
+
+ // // Events
+ // if(info->events.eventTypes.size() > 0) {
+ // line(&getVNEvent.body, "start", "");
+ // EventsGen::generate(&getVNEvent.body, &info->events, " ");
+ // line(&getVNEvent.body, ";", "");
+ // }
+
+ // // Wrap up methods
+ // line(&getAssets.body, "return assets;", "");
+ // line(&getVNEvent.body, "return start;", "");
+
+ // methodGen(&c.publicCode, vnStage);
+ // line(&c.publicCode, "", "");
+ // methodGen(&c.publicCode, getAssets);
+ // methodGen(&c.publicCode, getVNEvent);
+ // classGen(out, c);
+ // }
+ // };
+}
\ No newline at end of file