diff --git a/assets/games/liminal/prefabs/VNTextbox.xml b/assets/games/liminal/prefabs/VNTextbox.xml
index 25388ea3..7ff6f64a 100644
--- a/assets/games/liminal/prefabs/VNTextbox.xml
+++ b/assets/games/liminal/prefabs/VNTextbox.xml
@@ -1,5 +1,5 @@
-
+
-
-
+ >
+ test1
+
-
+
\ No newline at end of file
diff --git a/src/dawn/scene/components/ui/UIBorder.cpp b/src/dawn/scene/components/ui/UIBorder.cpp
index 3e8179e3..a4df06a6 100644
--- a/src/dawn/scene/components/ui/UIBorder.cpp
+++ b/src/dawn/scene/components/ui/UIBorder.cpp
@@ -25,6 +25,14 @@ float_t UIBorder::getContentHeight() {
return this->height;
}
+float_t UIBorder::getChildOffsetX() {
+ return this->borderSize._realValue.x;
+}
+
+float_t UIBorder::getChildOffsetY() {
+ return this->borderSize._realValue.y;
+}
+
std::vector UIBorder::getUIRenderPasses() {
struct ShaderPassItem item;
auto shader = getGame()->renderManager.uiShader;
diff --git a/src/dawn/scene/components/ui/UIBorder.hpp b/src/dawn/scene/components/ui/UIBorder.hpp
index bbe84b2e..d5b01709 100644
--- a/src/dawn/scene/components/ui/UIBorder.hpp
+++ b/src/dawn/scene/components/ui/UIBorder.hpp
@@ -24,6 +24,8 @@ namespace Dawn {
float_t getContentWidth() override;
float_t getContentHeight() override;
+ float_t getChildOffsetX() override;
+ float_t getChildOffsetY() override;
std::vector getUIRenderPasses() override;
void onStart() override;
};
diff --git a/src/dawn/scene/components/ui/UICanvas.cpp b/src/dawn/scene/components/ui/UICanvas.cpp
index 4f9b47fe..c867fbc7 100644
--- a/src/dawn/scene/components/ui/UICanvas.cpp
+++ b/src/dawn/scene/components/ui/UICanvas.cpp
@@ -62,6 +62,14 @@ float_t UICanvas::getContentHeight() {
return this->getHeight();
}
+float_t UICanvas::getChildOffsetX() {
+ return 0.0f;
+}
+
+float_t UICanvas::getChildOffsetY() {
+ return 0.0f;
+}
+
void UICanvas::onStart() {
if(camera == nullptr) camera = getScene()->findComponent();
diff --git a/src/dawn/scene/components/ui/UICanvas.hpp b/src/dawn/scene/components/ui/UICanvas.hpp
index 515e3a5e..ccc50fb6 100644
--- a/src/dawn/scene/components/ui/UICanvas.hpp
+++ b/src/dawn/scene/components/ui/UICanvas.hpp
@@ -39,6 +39,20 @@ namespace Dawn {
* @return Content height of this item.
*/
virtual float_t getContentHeight() = 0;
+
+ /**
+ * Returns the offset of the child elements of this UI item.
+ *
+ * @return Offset of the child elements of this UI item.
+ */
+ virtual float_t getChildOffsetX() = 0;
+
+ /**
+ * Returns the offset of the child elements of this UI item.
+ *
+ * @return Offset of the child elements of this UI item.
+ */
+ virtual float_t getChildOffsetY() = 0;
};
enum UIDrawType {
@@ -86,6 +100,8 @@ namespace Dawn {
float_t getHeight() override;
float_t getContentWidth() override;
float_t getContentHeight() override;
+ float_t getChildOffsetX() override;
+ float_t getChildOffsetY() override;
void onStart() override;
void onDispose() override;
};
diff --git a/src/dawn/scene/components/ui/UIComponent.cpp b/src/dawn/scene/components/ui/UIComponent.cpp
index d85a67a2..ada67e55 100644
--- a/src/dawn/scene/components/ui/UIComponent.cpp
+++ b/src/dawn/scene/components/ui/UIComponent.cpp
@@ -39,8 +39,8 @@ void UIComponent::updateAlignment() {
assertNotNull(dimensional);
float_t parentWidth, parentHeight;
- parentWidth = dimensional->getWidth();
- parentHeight = dimensional->getHeight();
+ parentWidth = dimensional->getContentWidth();
+ parentHeight = dimensional->getContentHeight();
UIComponent::calculateDimensions(
this->alignX,
@@ -63,6 +63,9 @@ void UIComponent::updateAlignment() {
glm::vec2(align[1], align[3])
);
+ translate.x += dimensional->getChildOffsetX();
+ translate.y += dimensional->getChildOffsetY();
+
this->transform->setLocalPosition(translate);
this->alignmentNeedsUpdating = false;
this->eventAlignmentUpdated.invoke();
@@ -180,6 +183,14 @@ float_t UIComponent::getHeight() {
return this->height;
}
+float_t UIComponent::getChildOffsetX() {
+ return 0;
+}
+
+float_t UIComponent::getChildOffsetY() {
+ return 0;
+}
+
void UIComponent::onStart() {
useEffect([&]{
this->alignmentNeedsUpdating = true;
diff --git a/src/dawn/scene/components/ui/UIComponent.hpp b/src/dawn/scene/components/ui/UIComponent.hpp
index d5560815..ab82f42d 100644
--- a/src/dawn/scene/components/ui/UIComponent.hpp
+++ b/src/dawn/scene/components/ui/UIComponent.hpp
@@ -109,6 +109,8 @@ namespace Dawn {
float_t getWidth() override;
float_t getHeight() override;
+ float_t getChildOffsetX() override;
+ float_t getChildOffsetY() override;
void onStart() override;
friend class UICanvas;
diff --git a/src/dawn/scene/components/ui/text/UILabel.cpp b/src/dawn/scene/components/ui/text/UILabel.cpp
index 6287c5ee..bb8f2577 100644
--- a/src/dawn/scene/components/ui/text/UILabel.cpp
+++ b/src/dawn/scene/components/ui/text/UILabel.cpp
@@ -25,7 +25,7 @@ void UILabel::onStart() {
}
std::vector UILabel::getUIRenderPasses() {
- // if(this->texts.size() == 0) return {};
+ if(this->textsBuffered.empty()) return {};
auto canvas = this->getCanvas();
auto shader = getGame()->renderManager.fontShader;
@@ -264,10 +264,12 @@ void UILabel::rebufferQuads(const std::vector newTexts) {
}
// Create mesh
- this->mesh.createBuffers(
- QUAD_VERTICE_COUNT * vertices.size(),
- QUAD_INDICE_COUNT * vertices.size()
- );
+ if(!vertices.empty()) {
+ this->mesh.createBuffers(
+ QUAD_VERTICE_COUNT * vertices.size(),
+ QUAD_INDICE_COUNT * vertices.size()
+ );
+ }
// Now buffer the quads.
int32_t j = 0;
diff --git a/src/dawn/scene/components/ui/text/UIRichTextLabel.cpp b/src/dawn/scene/components/ui/text/UIRichTextLabel.cpp
index ff02e905..882a783b 100644
--- a/src/dawn/scene/components/ui/text/UIRichTextLabel.cpp
+++ b/src/dawn/scene/components/ui/text/UIRichTextLabel.cpp
@@ -22,6 +22,11 @@ void UIRichTextLabel::onStart() {
struct UILabelStyle current;
styleStack.push_back(current);
std::vector bufferTexts;
+
+ if(this->richText._realValue.empty()) {
+ this->rebufferQuads(bufferTexts);
+ return;
+ }
std::function parseChildren = [&](Xml *node) {
if(node->children.empty()) {
diff --git a/src/dawn/scene/components/ui/text/UIRichTextLabel.hpp b/src/dawn/scene/components/ui/text/UIRichTextLabel.hpp
index e473775d..d1e612ab 100644
--- a/src/dawn/scene/components/ui/text/UIRichTextLabel.hpp
+++ b/src/dawn/scene/components/ui/text/UIRichTextLabel.hpp
@@ -9,6 +9,7 @@
namespace Dawn {
class UIRichTextLabel : public UILabel {
public:
+ // @innerXml
StateProperty richText;
UIRichTextLabel(SceneItem *item);
diff --git a/src/dawnliminal/scenes/HelloWorldScene.hpp b/src/dawnliminal/scenes/HelloWorldScene.hpp
index 29d17ed8..8b1dfc2b 100644
--- a/src/dawnliminal/scenes/HelloWorldScene.hpp
+++ b/src/dawnliminal/scenes/HelloWorldScene.hpp
@@ -8,6 +8,7 @@
#include "prefabs/SimpleSpinningCubePrefab.hpp"
#include "scene/components/display/Camera.hpp"
#include "scene/components/ui/text/UIRichTextLabel.hpp"
+#include "prefabs/VNTextbox.hpp"
namespace Dawn {
class HelloWorldScene : public Scene {
@@ -25,38 +26,15 @@ namespace Dawn {
auto canvas = canvasItem->addComponent();
canvas->camera = camera;
- auto newLabelItem = this->createSceneItem();
- auto newLabel = newLabelItem->addComponent();
- newLabel->alignment = glm::vec4(0, 0, 0, 0);
- newLabel->alignX = UI_COMPONENT_ALIGN_STRETCH;
- newLabel->alignY = UI_COMPONENT_ALIGN_STRETCH;
-
- // newLabel->maxWidth = 300.0f;
- newLabel->richText = std::string(
- ""
- "Hello World\nHow are you?"
- // "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
- // "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
- // "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
- // "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
- // "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
- // "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
- // "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
- // "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
- // "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
- // "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
- // "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
- // "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
- ""
- );
- newLabelItem->transform.setParent(canvas->transform);
+ auto vnTextbox = VNTextbox::prefabCreate(this);
+ vnTextbox->transform.setParent(canvas->transform);
}
std::vector getRequiredAssets() override {
auto assMan = &this->game->assetManager;
std::vector assets;
vectorAppend(&assets, SimpleSpinningCubePrefab::getRequiredAssets(assMan));
- assets.push_back(assMan->get("font_arial"));
+ vectorAppend(&assets, VNTextbox::prefabAssets(assMan));
return assets;
}
diff --git a/src/dawnshared/util/Xml.cpp b/src/dawnshared/util/Xml.cpp
index 5a4bf1cb..bcbe7870 100644
--- a/src/dawnshared/util/Xml.cpp
+++ b/src/dawnshared/util/Xml.cpp
@@ -31,6 +31,10 @@ void Xml::load(Xml *xml, std::string data, size_t *j) {
size_t i = *j;
while(c = data[i++]) {
+ if(insideTag) {
+ xml->outerXml += c;
+ }
+
switch(doing) {
case XML_PARSE_STATE_DOING_NOTHING:
if(c == '>') continue;
@@ -49,15 +53,23 @@ void Xml::load(Xml *xml, std::string data, size_t *j) {
Xml::load(child, data, &i);
xml->children.push_back(child);
doing = XML_PARSE_STATE_PARSING_CHILD;
+
+
+ // Remove last char since we kinda already parsed it.
+ xml->innerXml += child->outerXml;
+ xml->outerXml = xml->outerXml.substr(0, xml->outerXml.size()-1);
+ xml->outerXml += child->outerXml;
}
} else {
doing = XML_PARSE_STATE_PARSING_TAG_NAME;
level++;
insideTag = true;
+ xml->outerXml += c;
}
continue;
}
+ xml->innerXml += c;
if(Xml::isWhitespace(c)) continue;
doing = XML_PARSE_STATE_PARSING_VALUE;
buffer += c;
@@ -123,7 +135,9 @@ void Xml::load(Xml *xml, std::string data, size_t *j) {
case XML_PARSE_STATE_PARSING_ATTRIBUTE_VALUE:
// Parse the attribute value until we find a quote mark.
- if(c == '"') {
+ if(c == '\\') {
+ c = data[i++];
+ } else if(c == '"') {
doing = XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE;
xml->attributes[attrKey] = buffer;
buffer = "";
@@ -144,6 +158,8 @@ void Xml::load(Xml *xml, std::string data, size_t *j) {
continue;
}
+ xml->innerXml += c;
+
if(Xml::isWhitespace(c)) {
if(!valueIsInWhitespace) {
bufferWhitespaces.clear();
@@ -183,9 +199,16 @@ void Xml::load(Xml *xml, std::string data, size_t *j) {
i -= 1;
Xml::load(child, data, &i);
xml->children.push_back(child);
+
+ xml->innerXml += child->outerXml;
+ xml->outerXml = xml->outerXml.substr(0, xml->outerXml.size()-1);
+ xml->outerXml += child->outerXml;
}
- if(Xml::isWhitespace(c)) continue;
+ if(Xml::isWhitespace(c)) {
+ xml->innerXml += c;
+ continue;
+ }
// In HTML Spec there's a chance for there to be a value here, but not
// in the XML spec.
diff --git a/src/dawnshared/util/Xml.hpp b/src/dawnshared/util/Xml.hpp
index 44fa415b..8af4936f 100644
--- a/src/dawnshared/util/Xml.hpp
+++ b/src/dawnshared/util/Xml.hpp
@@ -32,6 +32,8 @@ namespace Dawn {
std::string node;
std::string value;
+ std::string innerXml;
+ std::string outerXml;
std::map attributes;
std::vector children;
diff --git a/src/dawnshared/util/parser/TypeParsers.hpp b/src/dawnshared/util/parser/TypeParsers.hpp
index ee93d732..cc612eec 100644
--- a/src/dawnshared/util/parser/TypeParsers.hpp
+++ b/src/dawnshared/util/parser/TypeParsers.hpp
@@ -12,6 +12,13 @@ namespace Dawn {
};
static inline std::string stringParser(std::string v, std::string *error) {
+ // Replace slashes and quotes
+ v = stringReplaceAll(v, "\\", "\\\\\\");
+ v = stringReplaceAll(v, "\"", "\\\"");
+
+ // Newlines.
+ v = stringReplaceAll(v, "\n", "\\n");
+
return "\"" + v + "\"";
};
diff --git a/src/dawnshared/util/string.hpp b/src/dawnshared/util/string.hpp
index 13092e31..c9260ea2 100644
--- a/src/dawnshared/util/string.hpp
+++ b/src/dawnshared/util/string.hpp
@@ -125,4 +125,26 @@ static inline std::string stringToLowercase(const std::string &str) {
}
);
return data;
+}
+
+/**
+ * Replace all instances of a string with another string within a string.
+ *
+ * @param str String to replace the contents of.
+ * @param needle Needle to look for.
+ * @param replace String to replace the needle with.
+ * @return A new string instance with the replacements made.
+ */
+static inline std::string stringReplaceAll(
+ const std::string &str,
+ const std::string &needle,
+ const std::string &replace
+) {
+ std::string newString = str;
+ size_t startPos = 0;
+ while((startPos = newString.find(needle, startPos)) != std::string::npos) {
+ newString.replace(startPos, needle.length(), replace);
+ startPos += replace.length();
+ }
+ return newString;
}
\ No newline at end of file
diff --git a/src/dawntools/util/parser/SceneItemComponentParser.cpp b/src/dawntools/util/parser/SceneItemComponentParser.cpp
index 7f40d48e..8583f800 100644
--- a/src/dawntools/util/parser/SceneItemComponentParser.cpp
+++ b/src/dawntools/util/parser/SceneItemComponentParser.cpp
@@ -66,5 +66,15 @@ int32_t SceneItemComponentParser::onParse(
++itOptional;
}
+ auto itInnerXml = ruleset.innerXml.begin();
+ while(itInnerXml != ruleset.innerXml.end()) {
+ auto name = itInnerXml->first;
+ auto type = itInnerXml->second;
+
+ out->values[name] = stringParser(node->innerXml, error);
+ if(error->size() != 0) return 1;
+ ++itInnerXml;
+ }
+
return 0;
}
\ No newline at end of file
diff --git a/src/dawntools/util/parser/SceneItemComponentRegistry.cpp b/src/dawntools/util/parser/SceneItemComponentRegistry.cpp
index b3bdbb85..8265ad30 100644
--- a/src/dawntools/util/parser/SceneItemComponentRegistry.cpp
+++ b/src/dawntools/util/parser/SceneItemComponentRegistry.cpp
@@ -76,14 +76,23 @@ struct SceneItemComponentRuleset SceneItemComponentRegistry::parseFile(
// Find each instance of "@optional" when it's used within a comment
// e.g. // @optional or /* @optional */ in the string data.1
- std::regex regex("^\\s*(?:\\/\\/|\\/\\*){1}\\s*\\@optional\\s*(?:\\*\\/)?\\s*$", regexFlags);
+ std::regex regex("^\\s*(?:\\/\\/|\\/\\*){1}\\s*\\@(optional|innerXml)\\s*(?:\\*\\/)?\\s*$", regexFlags);
std::sregex_iterator it(data.begin(), data.end(), regex);
std::sregex_iterator end;
while(it != end) {
+ // Extract the kind of parameter this is
+ std::smatch match;
+ if(!std::regex_search(data, match, regex)) {
+ std::cout << "Failed to determine parameter type!" << std::endl;
+ return { .name = "" };
+ }
+
+ std::string paramType = match[1].str();
+
// Find the next ";"
auto endPos = data.find(";", it->position() + it->length());
if(endPos == std::string::npos) {
- std::cout << "Failed to find end of line for optional attribute!" << std::endl;
+ std::cout << "Failed to find end of line for attribute!" << std::endl;
return { .name = "" };
}
@@ -105,16 +114,24 @@ struct SceneItemComponentRuleset SceneItemComponentRegistry::parseFile(
// Now (should) be able to extract the type;
std::regex regex2("^\\s*(?:[\\S]+<)?([\\w*:_\\s]+)(?:[\\S]+)? (\\**[\\w]+)\\s*$", regexFlags);
- std::smatch match;
- if(!std::regex_search(variableString, match, regex2)) {
+ std::smatch match2;
+ if(!std::regex_search(variableString, match2, regex2)) {
std::cout << "Failed to extract type and name from variable string! " << variableString << std::endl;
return { .name = "" };
}
// Now we have our type and name
- auto type = match[1].str();
- auto name = match[2].str();
- ruleset.selfOptional[name] = type;
+ auto type = match2[1].str();
+ auto name = match2[2].str();
+
+ // Now store depending on the type
+ if(paramType == "optional") {
+ ruleset.selfOptional[name] = type;
+ } else if(paramType == "innerXml") {
+ ruleset.innerXml[name] = type;
+ } else {
+ assertUnreachable();
+ }
++it;
}
return ruleset;
diff --git a/src/dawntools/util/parser/SceneItemComponentRegistry.hpp b/src/dawntools/util/parser/SceneItemComponentRegistry.hpp
index 5d6132cd..71dad60d 100644
--- a/src/dawntools/util/parser/SceneItemComponentRegistry.hpp
+++ b/src/dawntools/util/parser/SceneItemComponentRegistry.hpp
@@ -16,6 +16,7 @@ namespace Dawn {
std::string name;
std::string include;
std::map selfOptional;
+ std::map innerXml;
std::map optional;
std::vector extends;
};