343 lines
9.4 KiB
C++
343 lines
9.4 KiB
C++
/**
|
|
* 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 <iostream>
|
|
#include <vector>
|
|
|
|
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<std::string> split(std::string s, std::string delimiter) {
|
|
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
|
|
std::string token;
|
|
std::vector<std::string> 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<struct UIGenerated> *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<std::string> 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<std::string> 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<struct UIGenerated> 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;
|
|
} |