Major cleanup.

Moved to namespace
Cleanup includes
This commit is contained in:
Antoine Pilote
2021-07-11 18:56:44 -04:00
parent f77bef6b28
commit 0c6ed48bbd
174 changed files with 11772 additions and 11296 deletions

View File

@@ -1,106 +1,117 @@
#pragma once
#include "../Core/Core.h"
#include "src/Core/Core.h"
#include <src/Vendors/msdfgen/ext/import-font.h>
#include <map>
#include <src/Rendering/Textures/Texture.h>
#include "src/Core/Maths.h"
struct CharPos
namespace Nuake
{
double left;
double right;
double top;
double bottom;
};
struct CharUV
{
Vector2 Pos;
Vector2 Size;
};
class Char
{
private:
unsigned int m_VBO;
unsigned int m_VAO;
public:
unsigned int Unicode;
float Advance;
CharPos PlaneBounds;
CharUV AtlasBounds;
Char() {};
Char(const unsigned int unicode, float advance, CharPos plane, CharUV atlas)
struct CharPos
{
Unicode = unicode;
Advance = advance;
PlaneBounds = plane;
AtlasBounds = atlas;
}
double left;
double right;
double top;
double bottom;
};
CharUV GetAtlasUV(const Vector2& atlasSize)
struct CharUV
{
return AtlasBounds;
}
};
Vector2 Pos;
Vector2 Size;
};
class Font
{
private:
msdfgen::FreetypeHandle* ft;
msdfgen::FontHandle* font;
const char* fontFilename;
std::map<unsigned int, Char> Chars;
public:
Ref<Texture> FontAtlas;
Font() : ft(msdfgen::initializeFreetype()), font(nullptr), fontFilename(nullptr)
class Char
{
this->Chars = std::map<unsigned int ,Char>();
}
private:
unsigned int m_VBO;
unsigned int m_VAO;
~Font() {
if (ft) {
if (font)
msdfgen::destroyFont(font);
msdfgen::deinitializeFreetype(ft);
public:
unsigned int Unicode;
float Advance;
CharPos PlaneBounds;
CharUV AtlasBounds;
Char() {};
Char(const unsigned int unicode, float advance, CharPos plane, CharUV atlas)
{
Unicode = unicode;
Advance = advance;
PlaneBounds = plane;
AtlasBounds = atlas;
}
}
bool load(const char* fontFilename) {
if (ft && fontFilename) {
if (this->fontFilename && !strcmp(this->fontFilename, fontFilename))
return true;
if (font)
msdfgen::destroyFont(font);
if ((font = msdfgen::loadFont(ft, fontFilename))) {
this->fontFilename = fontFilename;
return true;
CharUV GetAtlasUV(const Vector2& atlasSize)
{
return AtlasBounds;
}
};
class Font
{
private:
msdfgen::FreetypeHandle* ft;
msdfgen::FontHandle* font;
const char* fontFilename;
std::map<unsigned int, Char> Chars;
public:
Ref<Texture> FontAtlas;
Font() : ft(msdfgen::initializeFreetype()), font(nullptr), fontFilename(nullptr)
{
this->Chars = std::map<unsigned int, Char>();
}
~Font()
{
if (ft)
{
if (font)
msdfgen::destroyFont(font);
msdfgen::deinitializeFreetype(ft);
}
this->fontFilename = nullptr;
}
return false;
}
operator msdfgen::FontHandle* () const {
return font;
}
bool load(const char* fontFilename)
{
if (ft && fontFilename)
{
if (this->fontFilename && !strcmp(this->fontFilename, fontFilename))
return true;
if (font)
msdfgen::destroyFont(font);
if ((font = msdfgen::loadFont(ft, fontFilename)))
{
this->fontFilename = fontFilename;
return true;
}
msdfgen::FontHandle* GetFontHandle() { return font; }
msdfgen::FreetypeHandle* GetFreetypeHandle() { return ft; }
this->fontFilename = nullptr;
}
return false;
}
void AddChar(const unsigned int unicode, float advance, CharPos plane, CharUV atlas)
{
this->Chars[unicode] = Char(unicode, advance, plane, atlas);
}
operator msdfgen::FontHandle* () const
{
return font;
}
Char GetChar(unsigned int unicode)
{
if (Chars.find(unicode) != Chars.end())
return Chars[unicode];
return Char();
}
};
msdfgen::FontHandle* GetFontHandle() { return font; }
msdfgen::FreetypeHandle* GetFreetypeHandle() { return ft; }
void AddChar(const unsigned int unicode, float advance, CharPos plane, CharUV atlas)
{
this->Chars[unicode] = Char(unicode, advance, plane, atlas);
}
Char GetChar(unsigned int unicode)
{
if (Chars.find(unicode) != Chars.end())
return Chars[unicode];
return Char();
}
};
}

View File

@@ -20,155 +20,159 @@
#include "../Rendering/Textures/Texture.h"
#include "msdf-atlas-gen/json-export.h"
typedef unsigned char byte;
struct Config
namespace Nuake
{
msdf_atlas::ImageType imageType;
msdf_atlas::ImageFormat imageFormat;
msdf_atlas::YDirection yDirection;
int width, height;
double emSize;
double pxRange;
double angleThreshold;
double miterLimit;
void (*edgeColoring)(msdfgen::Shape&, double, unsigned long long);
bool expensiveColoring;
unsigned long long coloringSeed;
msdf_atlas::GeneratorAttributes generatorAttributes;
bool preprocessGeometry;
bool kerning;
int threadCount = 1;
};
class FontLoader
{
public:
template <typename T, typename S, int N, msdf_atlas::GeneratorFunction<S, N> GEN_FN>
static bool makeAtlas(const std::vector<msdf_atlas::GlyphGeometry>& glyphs,
const std::vector<msdf_atlas::FontGeometry>& fonts,
Config& config, Ref<Font> font) {
// Create generator
msdf_atlas::ImmediateAtlasGenerator<S, N, GEN_FN, msdf_atlas::BitmapAtlasStorage<T, N> > generator(config.width, config.height);
// Setup generator settings
generator.setAttributes(config.generatorAttributes);
generator.setThreadCount(config.threadCount);
generator.generate(glyphs.data(), glyphs.size());
// Create bitmap
msdfgen::BitmapConstRef<T, N> bitmap = (msdfgen::BitmapConstRef<T, N>) generator.atlasStorage();
// Create Texture from bitmap
//msdf_atlas::exportJSON(fonts.data(), fonts.size(), config.emSize, config.pxRange, config.width, config.height, config.imageType, config.yDirection, "yayayayya.json", config.kerning);
font->FontAtlas = CreateRef<Texture>(Vector2(config.width, config.height), bitmap, true);
// Create Char structure
return true;
}
static Ref<Font> LoadFont(const std::string path)
struct Config
{
// create font
Ref<Font> font = CreateRef<Font>();
msdf_atlas::ImageType imageType;
msdf_atlas::ImageFormat imageFormat;
msdf_atlas::YDirection yDirection;
int width, height;
double emSize;
double pxRange;
double angleThreshold;
double miterLimit;
void (*edgeColoring)(msdfgen::Shape&, double, unsigned long long);
bool expensiveColoring;
unsigned long long coloringSeed;
msdf_atlas::GeneratorAttributes generatorAttributes;
bool preprocessGeometry;
bool kerning;
int threadCount = 1;
};
// Create atlas settings
Config config{};
config.pxRange = 2;
config.emSize = 0.0;
config.coloringSeed = 125155;
config.imageType = msdf_atlas::ImageType::MTSDF;
config.imageFormat = msdf_atlas::ImageFormat::UNSPECIFIED;
config.yDirection = msdf_atlas::YDirection::BOTTOM_UP;
config.edgeColoring = msdfgen::edgeColoringInkTrap;
config.kerning = true;
config.preprocessGeometry = false;
config.angleThreshold = 3.0;
config.miterLimit = 1.0;
config.generatorAttributes.scanlinePass = true;
config.generatorAttributes.config.overlapSupport = true;
class FontLoader
{
public:
// Load file
if (!font->load(path.c_str()))
Logger::Log("Failed to load font", CRITICAL);
// Load charset ASCII
std::vector<msdf_atlas::GlyphGeometry> glyphs;
std::vector<msdf_atlas::FontGeometry> fonts;
msdf_atlas::FontGeometry fontGeometry(&glyphs);
msdf_atlas::Charset charset = msdf_atlas::Charset::ASCII;
template <typename T, typename S, int N, msdf_atlas::GeneratorFunction<S, N> GEN_FN>
static bool makeAtlas(const std::vector<msdf_atlas::GlyphGeometry>& glyphs,
const std::vector<msdf_atlas::FontGeometry>& fonts,
Config& config, Ref<Font> font) {
// Create generator
msdf_atlas::ImmediateAtlasGenerator<S, N, GEN_FN, msdf_atlas::BitmapAtlasStorage<T, N> > generator(config.width, config.height);
// Load Create charset
float fontScale = 32;
bool preprocess = false;
int loaded = fontGeometry.loadCharset(font->GetFontHandle(), fontScale, charset, config.preprocessGeometry, config.kerning);
fonts.push_back(fontGeometry);
// Setup generator settings
generator.setAttributes(config.generatorAttributes);
generator.setThreadCount(config.threadCount);
generator.generate(glyphs.data(), glyphs.size());
if (glyphs.empty())
Logger::Log("No glyphs loaded.", CRITICAL);
// Create bitmap
msdfgen::BitmapConstRef<T, N> bitmap = (msdfgen::BitmapConstRef<T, N>) generator.atlasStorage();
// Create atlas params
msdf_atlas::TightAtlasPacker::DimensionsConstraint atlasSizeConstraint = msdf_atlas::TightAtlasPacker::DimensionsConstraint::MULTIPLE_OF_FOUR_SQUARE;
msdf_atlas::TightAtlasPacker atlasPacker;
atlasPacker.setDimensionsConstraint(atlasSizeConstraint);
msdf_atlas::ImageType imageType = msdf_atlas::ImageType::MTSDF;
atlasPacker.setPadding(imageType == msdf_atlas::ImageType::MSDF || imageType == msdf_atlas::ImageType::MTSDF ? 0 : -1);
atlasPacker.setPixelRange(config.pxRange);
atlasPacker.setUnitRange(config.emSize);
atlasPacker.setMiterLimit(config.miterLimit);
// Create Texture from bitmap
//msdf_atlas::exportJSON(fonts.data(), fonts.size(), config.emSize, config.pxRange, config.width, config.height, config.imageType, config.yDirection, "yayayayya.json", config.kerning);
font->FontAtlas = CreateRef<Texture>(Vector2(config.width, config.height), bitmap, true);
// Pack atlas
if (int remaining = atlasPacker.pack(glyphs.data(), glyphs.size())) {
if (remaining < 0) {
Logger::Log("Failed to pack atlas.", CRITICAL);
}
else {
printf("Error: Could not fit %d out of %d glyphs into the atlas.\n", remaining, (int)glyphs.size());
}
}
// update atlast size
atlasPacker.getDimensions(config.width, config.height);
if (!(config.width > 0 && config.height > 0))
printf("Unable to determine atlas size.");
config.emSize = atlasPacker.getScale();
config.pxRange = atlasPacker.getPixelRange();
// Color the glyph
//unsigned long long glyphSeed = config.coloringSeed;
//for (msdf_atlas::GlyphGeometry& glyph : glyphs) {
// glyphSeed *= 6364136223846793005ull;
// glyph.edgeColoring(config.edgeColoring, config.angleThreshold, glyphSeed);
//}
msdf_atlas::Workload([&glyphs, &config](int i, int threadNo) -> bool {
unsigned long long glyphSeed = (6364136223846793005ull * (config.coloringSeed ^ i) + 1442695040888963407ull) * !!config.coloringSeed;
glyphs[i].edgeColoring(config.edgeColoring, config.angleThreshold, glyphSeed);
// Create Char structure
return true;
}, glyphs.size()).finish(config.threadCount);
// Create bitmap and char structure
auto bitmap = makeAtlas<byte, float, 4, msdf_atlas::mtsdfGenerator>(glyphs, fonts, config, font);
for (auto& g : glyphs)
{
CharPos plane = {};
g.getQuadPlaneBounds(plane.left, plane.bottom, plane.right, plane.top);
CharUV box = {};
double x2, y2, z2, w2;
g.getQuadAtlasBounds(x2, y2, z2, w2);
box.Pos.x = x2;
box.Pos.y = y2;
box.Size.x = z2;
box.Size.y = w2;
font->AddChar(g.getCodepoint(), g.getAdvance(), plane, box);
}
static Ref<Font> LoadFont(const std::string path)
{
// create font
Ref<Font> font = CreateRef<Font>();
return font;
}
};
// Create atlas settings
Config config{};
config.pxRange = 2;
config.emSize = 0.0;
config.coloringSeed = 125155;
config.imageType = msdf_atlas::ImageType::MTSDF;
config.imageFormat = msdf_atlas::ImageFormat::UNSPECIFIED;
config.yDirection = msdf_atlas::YDirection::BOTTOM_UP;
config.edgeColoring = msdfgen::edgeColoringInkTrap;
config.kerning = true;
config.preprocessGeometry = false;
config.angleThreshold = 3.0;
config.miterLimit = 1.0;
config.generatorAttributes.scanlinePass = true;
config.generatorAttributes.config.overlapSupport = true;
// Load file
if (!font->load(path.c_str()))
Logger::Log("Failed to load font", CRITICAL);
// Load charset ASCII
std::vector<msdf_atlas::GlyphGeometry> glyphs;
std::vector<msdf_atlas::FontGeometry> fonts;
msdf_atlas::FontGeometry fontGeometry(&glyphs);
msdf_atlas::Charset charset = msdf_atlas::Charset::ASCII;
// Load Create charset
float fontScale = 32;
bool preprocess = false;
int loaded = fontGeometry.loadCharset(font->GetFontHandle(), fontScale, charset, config.preprocessGeometry, config.kerning);
fonts.push_back(fontGeometry);
if (glyphs.empty())
Logger::Log("No glyphs loaded.", CRITICAL);
// Create atlas params
msdf_atlas::TightAtlasPacker::DimensionsConstraint atlasSizeConstraint = msdf_atlas::TightAtlasPacker::DimensionsConstraint::MULTIPLE_OF_FOUR_SQUARE;
msdf_atlas::TightAtlasPacker atlasPacker;
atlasPacker.setDimensionsConstraint(atlasSizeConstraint);
msdf_atlas::ImageType imageType = msdf_atlas::ImageType::MTSDF;
atlasPacker.setPadding(imageType == msdf_atlas::ImageType::MSDF || imageType == msdf_atlas::ImageType::MTSDF ? 0 : -1);
atlasPacker.setPixelRange(config.pxRange);
atlasPacker.setUnitRange(config.emSize);
atlasPacker.setMiterLimit(config.miterLimit);
// Pack atlas
if (int remaining = atlasPacker.pack(glyphs.data(), glyphs.size())) {
if (remaining < 0) {
Logger::Log("Failed to pack atlas.", CRITICAL);
}
else {
printf("Error: Could not fit %d out of %d glyphs into the atlas.\n", remaining, (int)glyphs.size());
}
}
// update atlast size
atlasPacker.getDimensions(config.width, config.height);
if (!(config.width > 0 && config.height > 0))
printf("Unable to determine atlas size.");
config.emSize = atlasPacker.getScale();
config.pxRange = atlasPacker.getPixelRange();
// Color the glyph
//unsigned long long glyphSeed = config.coloringSeed;
//for (msdf_atlas::GlyphGeometry& glyph : glyphs) {
// glyphSeed *= 6364136223846793005ull;
// glyph.edgeColoring(config.edgeColoring, config.angleThreshold, glyphSeed);
//}
msdf_atlas::Workload([&glyphs, &config](int i, int threadNo) -> bool {
unsigned long long glyphSeed = (6364136223846793005ull * (config.coloringSeed ^ i) + 1442695040888963407ull) * !!config.coloringSeed;
glyphs[i].edgeColoring(config.edgeColoring, config.angleThreshold, glyphSeed);
return true;
}, glyphs.size()).finish(config.threadCount);
// Create bitmap and char structure
auto bitmap = makeAtlas<byte, float, 4, msdf_atlas::mtsdfGenerator>(glyphs, fonts, config, font);
for (auto& g : glyphs)
{
CharPos plane = {};
g.getQuadPlaneBounds(plane.left, plane.bottom, plane.right, plane.top);
CharUV box = {};
double x2, y2, z2, w2;
g.getQuadAtlasBounds(x2, y2, z2, w2);
box.Pos.x = x2;
box.Pos.y = y2;
box.Size.x = z2;
box.Size.y = w2;
font->AddChar(g.getCodepoint(), g.getAdvance(), plane, box);
}
return font;
}
};
}

View File

@@ -1,20 +1,22 @@
#include "FontManager.h"
std::map <std::string, Ref<Font>> FontManager::m_Fonts = std::map<std::string, Ref<Font>>();
namespace Nuake {
std::map <std::string, Ref<Font>> FontManager::m_Fonts = std::map<std::string, Ref<Font>>();
Ref<Font> FontManager::GetFont(const std::string& font)
{
// Fonts exists in memory
if (m_Fonts.find(font) != m_Fonts.end())
Ref<Font> FontManager::GetFont(const std::string& font)
{
return m_Fonts[font];
}
// Load font
Ref<Font> newFont = FontLoader::LoadFont(font);
if (newFont)
return newFont;
// Fonts exists in memory
if (m_Fonts.find(font) != m_Fonts.end())
{
return m_Fonts[font];
}
Logger::Log("Error: failed to load font " + font, CRITICAL);
return nullptr;
}
// Load font
Ref<Font> newFont = FontLoader::LoadFont(font);
if (newFont)
return newFont;
Logger::Log("Error: failed to load font " + font, CRITICAL);
return nullptr;
}
}

View File

@@ -2,11 +2,14 @@
#include <map>
#include "FontLoader.h"
class FontManager
{
private:
static std::map <std::string, Ref<Font>> m_Fonts;
public:
static Ref<Font> GetFont(const std::string& font);
};
namespace Nuake {
class FontManager
{
private:
static std::map <std::string, Ref<Font>> m_Fonts;
public:
static Ref<Font> GetFont(const std::string& font);
};
}

View File

@@ -1,282 +1,286 @@
#include "InterfaceParser.h"
#include "Styling/Stylesheet.h"
Ref<Canvas> InterfaceParser::Root = CreateRef<Canvas>();
void InterfaceParser::Iterate(const pugi::xml_node& xml_node, Ref<Node> node, int depth)
namespace Nuake
{
int currentDepth = depth + 1;
for (auto& e : xml_node.children())
Ref<Canvas> InterfaceParser::Root = CreateRef<Canvas>();
void InterfaceParser::Iterate(const pugi::xml_node& xml_node, Ref<Node> node, int depth)
{
std::string type = e.name();
Ref<Node> newNode;
if (type == "Canvas")
newNode = CreateCanvas(e);
else if (type == "Rect")
newNode = CreateNode(e);
else if (type == "p")
newNode = CreateTextNode(e);
else
continue;
newNode->Depth = currentDepth;
node->Childrens.push_back(newNode);
Iterate(e, newNode, currentDepth);
}
}
Ref<Canvas> InterfaceParser::Parse(const std::string path)
{
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(path.c_str());
std::string name = doc.first_child().name();
if (name != "Canvas")
{
Logger::Log("InterfaceParser error: First child should be a canvas - " + path, CRITICAL);
return nullptr;
}
Root = CreateCanvas(doc.first_child());
Root->Depth = 0;
Iterate(doc.first_child(), Root, 0);
return Root;
}
Ref<TextNode> InterfaceParser::CreateTextNode(const pugi::xml_node& xml_node)
{
Ref<TextNode> node = CreateRef<TextNode>();
node->content = xml_node.text().as_string();
node->Type = NodeType::Text;
TextStyle style{
FontManager::GetFont("resources/Fonts/RobotoMono-Regular.ttf"),
2.0,
Color(255, 255, 255, 255)
};
node->SetTextStyle(style);
for (auto& a : xml_node.attributes())
{
std::string name = a.name();
if (name == "groups")
int currentDepth = depth + 1;
for (auto& e : xml_node.children())
{
for (auto& g : split(a.value(), ' '))
{
node->AddGroup(g);
}
}
if (name == "height")
node->Height = GetUnit(a.value());
if (name == "width")
node->Width = GetUnit(a.value());
if (name == "margin")
node->Margin = GetVec4Unit(a.value());
if (name == "padding")
node->Padding = GetVec4Unit(a.value());
if (name == "border")
node->Border = GetVec4Unit(a.value());
if (name == "position")
node->Position = GetVec4Unit(a.value());
if (name == "color")
node->BackgroundColor = GetColor(a.value());
}
return node;
}
std::string type = e.name();
Ref<Node> newNode;
Ref<Node> InterfaceParser::CreateNode(const pugi::xml_node& xml_node)
{
Ref<Node> node = CreateRef<Node>();
node->Root = Root;
for (auto& a : xml_node.attributes())
{
std::string name = a.name();
if (name == "groups")
{
for (auto& g : split(a.value(), ' '))
{
node->AddGroup(g);
}
}
if (name == "height")
node->Height = GetUnit(a.value());
if (name == "width")
node->Width = GetUnit(a.value());
if (name == "margin")
node->Margin = GetVec4Unit(a.value());
if (name == "padding")
node->Padding = GetVec4Unit(a.value());
if (name == "border")
node->Border = GetVec4Unit(a.value());
if (name == "position")
node->Position = GetVec4Unit(a.value());
if (name == "color")
node->BackgroundColor = GetColor(a.value());
if (name == "onclick")
{
std::string signature = a.value();
Root->Script->RegisterMethod(a.value());
node->OnClickSignature = a.value();
}
}
return node;
}
Layout::LayoutUnit InterfaceParser::GetUnit(const std::string& value)
{
std::regex only_number("[0-9]+");
std::regex not_number("[^0-9]+");
// is percentage
std::smatch match_value;
if (std::regex_search(value.begin(), value.end(), match_value, only_number))
{
std::smatch match_type;
if (std::regex_search(value.begin(), value.end(), match_type, not_number))
{
float value = std::stof(match_value[0]);
if (match_type[0] == "%")
{
return Layout::LayoutUnit{
value,
Layout::Unit::PERCENT
};
}
else if (match_type[0] == "px")
{
return Layout::LayoutUnit{
value,
Layout::Unit::PIXEL
};
}
}
}
}
std::vector<std::string> InterfaceParser::split(std::string const& str, const char delim)
{
std::vector<std::string> result;
size_t start;
size_t end = 0;
while ((start = str.find_first_not_of(delim, end)) != std::string::npos)
{
end = str.find(delim, start);
result.push_back(str.substr(start, end - start));
}
return result;
}
Layout::LayoutVec4 InterfaceParser::GetVec4Unit(const std::string& value)
{
std::regex regex("[0-9]+[^ ]+");
std::smatch match_value;
Layout::LayoutVec4 result;
std::vector<std::string> splits = split(value, ' ');
int idx = 0;
for (auto& s : splits)
{
if (std::regex_search(value.begin(), value.end(), match_value, regex))
{
if (idx == 0)
{
result.Left = GetUnit(s);
}
else if (idx == 1)
{
result.Right = GetUnit(s);
}
else if (idx == 2)
{
result.Top = GetUnit(s);
}
if (type == "Canvas")
newNode = CreateCanvas(e);
else if (type == "Rect")
newNode = CreateNode(e);
else if (type == "p")
newNode = CreateTextNode(e);
else
{
result.Bottom = GetUnit(s);
}
idx++;
continue;
newNode->Depth = currentDepth;
node->Childrens.push_back(newNode);
Iterate(e, newNode, currentDepth);
}
}
return result;
}
Color InterfaceParser::GetColor(const std::string& value)
{
std::regex regex("[0-9]+[^ ]+");
std::smatch match_value;
Color result;
std::vector<std::string> splits = split(value, ' ');
int idx = 0;
for (auto& s : splits)
Ref<Canvas> InterfaceParser::Parse(const std::string path)
{
if (std::regex_search(value.begin(), value.end(), match_value, regex))
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(path.c_str());
std::string name = doc.first_child().name();
if (name != "Canvas")
{
if (idx == 0)
{
result.r = std::stof(s);
}
else if (idx == 1)
{
result.g = std::stof(s);
}
else if (idx == 2)
{
result.b = std::stof(s);
}
else
{
result.a = std::stof(s);
}
idx++;
Logger::Log("InterfaceParser error: First child should be a canvas - " + path, CRITICAL);
return nullptr;
}
}
return result;
}
Ref<Canvas> InterfaceParser::CreateCanvas(const pugi::xml_node& xml_node)
{
Ref<Canvas> node = CreateRef<Canvas>();
node->Root = Root;
for (auto& a : xml_node.attributes())
Root = CreateCanvas(doc.first_child());
Root->Depth = 0;
Iterate(doc.first_child(), Root, 0);
return Root;
}
Ref<TextNode> InterfaceParser::CreateTextNode(const pugi::xml_node& xml_node)
{
std::string name = a.name();
if (name == "groups")
Ref<TextNode> node = CreateRef<TextNode>();
node->content = xml_node.text().as_string();
node->Type = NodeType::Text;
TextStyle style{
FontManager::GetFont("resources/Fonts/RobotoMono-Regular.ttf"),
2.0,
Color(255, 255, 255, 255)
};
node->SetTextStyle(style);
for (auto& a : xml_node.attributes())
{
for (auto& g : split(a.value(), ' '))
std::string name = a.name();
if (name == "groups")
{
node->AddGroup(g);
for (auto& g : split(a.value(), ' '))
{
node->AddGroup(g);
}
}
if (name == "height")
node->Height = GetUnit(a.value());
if (name == "width")
node->Width = GetUnit(a.value());
if (name == "margin")
node->Margin = GetVec4Unit(a.value());
if (name == "padding")
node->Padding = GetVec4Unit(a.value());
if (name == "border")
node->Border = GetVec4Unit(a.value());
if (name == "position")
node->Position = GetVec4Unit(a.value());
if (name == "color")
node->BackgroundColor = GetColor(a.value());
}
return node;
}
Ref<Node> InterfaceParser::CreateNode(const pugi::xml_node& xml_node)
{
Ref<Node> node = CreateRef<Node>();
node->Root = Root;
for (auto& a : xml_node.attributes())
{
std::string name = a.name();
if (name == "groups")
{
for (auto& g : split(a.value(), ' '))
{
node->AddGroup(g);
}
}
if (name == "height")
node->Height = GetUnit(a.value());
if (name == "width")
node->Width = GetUnit(a.value());
if (name == "margin")
node->Margin = GetVec4Unit(a.value());
if (name == "padding")
node->Padding = GetVec4Unit(a.value());
if (name == "border")
node->Border = GetVec4Unit(a.value());
if (name == "position")
node->Position = GetVec4Unit(a.value());
if (name == "color")
node->BackgroundColor = GetColor(a.value());
if (name == "onclick")
{
std::string signature = a.value();
Root->Script->RegisterMethod(a.value());
node->OnClickSignature = a.value();
}
}
if (name == "height")
node->Height = GetUnit(a.value());
if (name == "width")
node->Width = GetUnit(a.value());
if (name == "margin")
node->Margin = GetVec4Unit(a.value());
if (name == "padding")
node->Padding = GetVec4Unit(a.value());
if (name == "border")
node->Border = GetVec4Unit(a.value());
if (name == "position")
node->Position = GetVec4Unit(a.value());
if (name == "color")
node->BackgroundColor = GetColor(a.value());
if (name == "script")
return node;
}
Layout::LayoutUnit InterfaceParser::GetUnit(const std::string& value)
{
std::regex only_number("[0-9]+");
std::regex not_number("[^0-9]+");
// is percentage
std::smatch match_value;
if (std::regex_search(value.begin(), value.end(), match_value, only_number))
{
auto s = split(a.value(), ' ');
std::string path = s[0];
std::string module = s[1];
node->Script = ScriptingEngine::RegisterScript(path, module);
}
if (name == "stylesheet")
{
std::string path = a.value();
node->StyleSheet = UI::StyleSheet::New(path);
std::smatch match_type;
if (std::regex_search(value.begin(), value.end(), match_type, not_number))
{
float value = std::stof(match_value[0]);
if (match_type[0] == "%")
{
return Layout::LayoutUnit{
value,
Layout::Unit::PERCENT
};
}
else if (match_type[0] == "px")
{
return Layout::LayoutUnit{
value,
Layout::Unit::PIXEL
};
}
}
}
}
return node;
}
std::vector<std::string> InterfaceParser::split(std::string const& str, const char delim)
{
std::vector<std::string> result;
size_t start;
size_t end = 0;
while ((start = str.find_first_not_of(delim, end)) != std::string::npos)
{
end = str.find(delim, start);
result.push_back(str.substr(start, end - start));
}
return result;
}
Layout::LayoutVec4 InterfaceParser::GetVec4Unit(const std::string& value)
{
std::regex regex("[0-9]+[^ ]+");
std::smatch match_value;
Layout::LayoutVec4 result;
std::vector<std::string> splits = split(value, ' ');
int idx = 0;
for (auto& s : splits)
{
if (std::regex_search(value.begin(), value.end(), match_value, regex))
{
if (idx == 0)
{
result.Left = GetUnit(s);
}
else if (idx == 1)
{
result.Right = GetUnit(s);
}
else if (idx == 2)
{
result.Top = GetUnit(s);
}
else
{
result.Bottom = GetUnit(s);
}
idx++;
}
}
return result;
}
Color InterfaceParser::GetColor(const std::string& value)
{
std::regex regex("[0-9]+[^ ]+");
std::smatch match_value;
Color result;
std::vector<std::string> splits = split(value, ' ');
int idx = 0;
for (auto& s : splits)
{
if (std::regex_search(value.begin(), value.end(), match_value, regex))
{
if (idx == 0)
{
result.r = std::stof(s);
}
else if (idx == 1)
{
result.g = std::stof(s);
}
else if (idx == 2)
{
result.b = std::stof(s);
}
else
{
result.a = std::stof(s);
}
idx++;
}
}
return result;
}
Ref<Canvas> InterfaceParser::CreateCanvas(const pugi::xml_node& xml_node)
{
Ref<Canvas> node = CreateRef<Canvas>();
node->Root = Root;
for (auto& a : xml_node.attributes())
{
std::string name = a.name();
if (name == "groups")
{
for (auto& g : split(a.value(), ' '))
{
node->AddGroup(g);
}
}
if (name == "height")
node->Height = GetUnit(a.value());
if (name == "width")
node->Width = GetUnit(a.value());
if (name == "margin")
node->Margin = GetVec4Unit(a.value());
if (name == "padding")
node->Padding = GetVec4Unit(a.value());
if (name == "border")
node->Border = GetVec4Unit(a.value());
if (name == "position")
node->Position = GetVec4Unit(a.value());
if (name == "color")
node->BackgroundColor = GetColor(a.value());
if (name == "script")
{
auto s = split(a.value(), ' ');
std::string path = s[0];
std::string module = s[1];
node->Script = ScriptingEngine::RegisterScript(path, module);
}
if (name == "stylesheet")
{
std::string path = a.value();
node->StyleSheet = UI::StyleSheet::New(path);
}
}
return node;
}
}

View File

@@ -9,22 +9,26 @@
#include "Nodes/TextNode.h"
#include "Font/FontManager.h"
#include "../Scripting/ScriptingEngine.h"
class InterfaceParser
namespace Nuake
{
private:
static Ref<Canvas> Root;
public:
static Ref<Canvas> Parse(const std::string path);
class InterfaceParser
{
private:
static Ref<Canvas> Root;
public:
static Ref<Canvas> Parse(const std::string path);
static void Iterate(const pugi::xml_node& xml_node, Ref<Node> node, int depth);
static void Iterate(const pugi::xml_node& xml_node, Ref<Node> node, int depth);
static Ref<Node> CreateNode(const pugi::xml_node& xml_node);
static Ref<Canvas> CreateCanvas(const pugi::xml_node& xml_node);
static Ref<TextNode> CreateTextNode(const pugi::xml_node& xml_node);
static Ref<Node> CreateNode(const pugi::xml_node& xml_node);
static Ref<Canvas> CreateCanvas(const pugi::xml_node& xml_node);
static Ref<TextNode> CreateTextNode(const pugi::xml_node& xml_node);
static std::vector<std::string> split(std::string const& str, const char delim);
static std::vector<std::string> split(std::string const& str, const char delim);
static Layout::LayoutUnit GetUnit(const std::string& value);
static Layout::LayoutVec4 GetVec4Unit(const std::string& value);
static Color GetColor(const std::string& value);
};
static Layout::LayoutUnit GetUnit(const std::string& value);
static Layout::LayoutVec4 GetVec4Unit(const std::string& value);
static Color GetColor(const std::string& value);
};
}

View File

@@ -1,5 +1,9 @@
#include "Canvas.h"
Canvas::Canvas()
{
namespace Nuake {
Canvas::Canvas()
{
}
}

View File

@@ -5,15 +5,15 @@
#include <map>
#include "../Styling/Stylesheet.h"
// Base container for UI.
class Canvas : public Node
{
private:
// Script here
namespace Nuake {
class Canvas : public Node
{
private:
public:
Ref<WrenScript> Script;
Ref<UI::StyleSheet> StyleSheet;
public:
Ref<WrenScript> Script;
Ref<UI::StyleSheet> StyleSheet;
Canvas();
};
Canvas();
};
}

View File

@@ -1,141 +1,144 @@
#include "Node.h"
Node::Node()
namespace Nuake
{
Childrens = std::vector<Ref<Node>>();
Groups = std::vector<std::string>();
PositionType = Layout::PositionType::RELATIVE;
Position = Layout::LayoutVec4();
Height = MaxHeight = MinHeight = Layout::LayoutUnit();
Margin = Padding = Border = Layout::LayoutVec4();
Direction = Layout::LayoutDirection::LTR;
FlexDirection = Layout::FlexDirection::ROW;
FlexWrap = Layout::FlexWrap::WRAP;
FlexGrow = 0.f;
FlexShrink = 1.f;
FlexBasis = 10.f;
AspectRatio = 1.f;
AlignItems = Layout::AlignItems::AUTO;
AlignSelf = Layout::AlignItems::AUTO;
}
void Node::ApplyStyle(Ref<StyleGroup> stylegroup)
{
for (auto& s : stylegroup->GetProps())
Node::Node()
{
switch (s.first)
{
case PropType::HEIGHT:
{
Height.Unit = (Layout::Unit)(s.second.type);
float value = s.second.value.Number;
Height.Value = value;
}
break;
case PropType::MIN_HEIGHT:
MinHeight.Unit = (Layout::Unit)s.second.type;
MinHeight.Value = s.second.value.Number;
break;
case PropType::MAX_HEIGHT:
MaxHeight.Unit = (Layout::Unit)s.second.type;
MaxHeight.Value = s.second.value.Number;
break;
case PropType::WIDTH:
Width.Unit = (Layout::Unit)s.second.type;
Width.Value = s.second.value.Number;
break;
case PropType::MIN_WIDTH:
MinWidth.Unit = (Layout::Unit)s.second.type;
MinWidth.Value = s.second.value.Number;
break;
case PropType::MAX_WIDTH:
MaxWidth.Unit = (Layout::Unit)s.second.type;
MaxWidth.Value = s.second.value.Number;
break;
case PropType::MARGIN_RIGHT:
Margin.Right.Unit = (Layout::Unit)s.second.type;
Margin.Right.Value = s.second.value.Number;
break;
case PropType::MARGIN_LEFT:
Margin.Left.Unit = (Layout::Unit)s.second.type;
Margin.Left.Value = s.second.value.Number;
break;
case PropType::MARGIN_TOP:
Margin.Top.Unit = (Layout::Unit)s.second.type;
Margin.Top.Value = s.second.value.Number;
break;
case PropType::MARGIN_BOTTOM:
Margin.Bottom.Unit = (Layout::Unit)s.second.type;
Margin.Bottom.Value = s.second.value.Number;
break;
case PropType::JUSTIFY_CONTENT:
JustifyContent = (Layout::JustifyContent)s.second.value.Enum;
break;
case PropType::FLEX_WRAP:
FlexWrap = (Layout::FlexWrap)s.second.value.Enum;
break;
case PropType::FLEX_DIRECTION:
FlexDirection = (Layout::FlexDirection)s.second.value.Enum;
break;
case PropType::ALIGN_ITEMS:
AlignItems = (Layout::AlignItems)s.second.value.Enum;
break;
case PropType::SELF_ALIGN:
AlignSelf = (Layout::AlignItems)s.second.value.Enum;
break;
case PropType::ALIGN_CONTENT:
AlignContent = (Layout::AlignContent)s.second.value.Enum;
break;
case PropType::POSITION:
PositionType = (Layout::PositionType)s.second.value.Enum;
break;
case PropType::LEFT:
Position.Left.Unit = (Layout::Unit)s.second.type;
Position.Left.Value = s.second.value.Number;
break;
case PropType::RIGHT:
Position.Right.Unit = (Layout::Unit)s.second.type;
Position.Right.Value = s.second.value.Number;
break;
case PropType::TOP:
Position.Top.Unit = (Layout::Unit)s.second.type;
Position.Top.Value = s.second.value.Number;
break;
case PropType::BOTTOM:
Position.Bottom.Unit = (Layout::Unit)s.second.type;
Position.Bottom.Value = s.second.value.Number;
break;
}
}
}
bool Node::IsPositionInside(Vector2 position)
{
float width = YGNodeLayoutGetWidth(YogaNode);
float height = YGNodeLayoutGetHeight(YogaNode);
float padding = YGNodeLayoutGetPadding(YogaNode, YGEdgeLeft);
float left = YGNodeLayoutGetLeft(YogaNode); //+ offset.x;
float top = YGNodeLayoutGetTop(YogaNode);// +offset.y;
float parentLeft = 0.0f;
float parentTop = 0.0f;
auto parent = YGNodeGetParent(YogaNode);
if (parent)
{
parentLeft = YGNodeLayoutGetLeft(YGNodeGetParent(YogaNode));
parentTop = YGNodeLayoutGetTop(YGNodeGetParent(YogaNode));
float parentPaddingTop = YGNodeLayoutGetPadding(parent, YGEdgeTop);
float parentPaddingLeft = YGNodeLayoutGetPadding(parent, YGEdgeTop);
// Overflow hidden.
float parentwidth = YGNodeLayoutGetWidth(parent);
if (parentwidth - YGNodeLayoutGetMargin(YogaNode, YGEdgeLeft) < width)
width = parentwidth - parentPaddingLeft;
float parentHeight = YGNodeLayoutGetHeight(parent);
if (parentHeight < height)
height = parentHeight - parentPaddingTop;
Childrens = std::vector<Ref<Node>>();
Groups = std::vector<std::string>();
PositionType = Layout::PositionType::RELATIVE;
Position = Layout::LayoutVec4();
Height = MaxHeight = MinHeight = Layout::LayoutUnit();
Margin = Padding = Border = Layout::LayoutVec4();
Direction = Layout::LayoutDirection::LTR;
FlexDirection = Layout::FlexDirection::ROW;
FlexWrap = Layout::FlexWrap::WRAP;
FlexGrow = 0.f;
FlexShrink = 1.f;
FlexBasis = 10.f;
AspectRatio = 1.f;
AlignItems = Layout::AlignItems::AUTO;
AlignSelf = Layout::AlignItems::AUTO;
}
left += parentLeft;
top += parentTop;
return position.x > left && position.x < left + width && position.y > top && position.y < top + height;
}
void Node::ApplyStyle(Ref<StyleGroup> stylegroup)
{
for (auto& s : stylegroup->GetProps())
{
switch (s.first)
{
case PropType::HEIGHT:
{
Height.Unit = (Layout::Unit)(s.second.type);
float value = s.second.value.Number;
Height.Value = value;
}
break;
case PropType::MIN_HEIGHT:
MinHeight.Unit = (Layout::Unit)s.second.type;
MinHeight.Value = s.second.value.Number;
break;
case PropType::MAX_HEIGHT:
MaxHeight.Unit = (Layout::Unit)s.second.type;
MaxHeight.Value = s.second.value.Number;
break;
case PropType::WIDTH:
Width.Unit = (Layout::Unit)s.second.type;
Width.Value = s.second.value.Number;
break;
case PropType::MIN_WIDTH:
MinWidth.Unit = (Layout::Unit)s.second.type;
MinWidth.Value = s.second.value.Number;
break;
case PropType::MAX_WIDTH:
MaxWidth.Unit = (Layout::Unit)s.second.type;
MaxWidth.Value = s.second.value.Number;
break;
case PropType::MARGIN_RIGHT:
Margin.Right.Unit = (Layout::Unit)s.second.type;
Margin.Right.Value = s.second.value.Number;
break;
case PropType::MARGIN_LEFT:
Margin.Left.Unit = (Layout::Unit)s.second.type;
Margin.Left.Value = s.second.value.Number;
break;
case PropType::MARGIN_TOP:
Margin.Top.Unit = (Layout::Unit)s.second.type;
Margin.Top.Value = s.second.value.Number;
break;
case PropType::MARGIN_BOTTOM:
Margin.Bottom.Unit = (Layout::Unit)s.second.type;
Margin.Bottom.Value = s.second.value.Number;
break;
case PropType::JUSTIFY_CONTENT:
JustifyContent = (Layout::JustifyContent)s.second.value.Enum;
break;
case PropType::FLEX_WRAP:
FlexWrap = (Layout::FlexWrap)s.second.value.Enum;
break;
case PropType::FLEX_DIRECTION:
FlexDirection = (Layout::FlexDirection)s.second.value.Enum;
break;
case PropType::ALIGN_ITEMS:
AlignItems = (Layout::AlignItems)s.second.value.Enum;
break;
case PropType::SELF_ALIGN:
AlignSelf = (Layout::AlignItems)s.second.value.Enum;
break;
case PropType::ALIGN_CONTENT:
AlignContent = (Layout::AlignContent)s.second.value.Enum;
break;
case PropType::POSITION:
PositionType = (Layout::PositionType)s.second.value.Enum;
break;
case PropType::LEFT:
Position.Left.Unit = (Layout::Unit)s.second.type;
Position.Left.Value = s.second.value.Number;
break;
case PropType::RIGHT:
Position.Right.Unit = (Layout::Unit)s.second.type;
Position.Right.Value = s.second.value.Number;
break;
case PropType::TOP:
Position.Top.Unit = (Layout::Unit)s.second.type;
Position.Top.Value = s.second.value.Number;
break;
case PropType::BOTTOM:
Position.Bottom.Unit = (Layout::Unit)s.second.type;
Position.Bottom.Value = s.second.value.Number;
break;
}
}
}
bool Node::IsPositionInside(Vector2 position)
{
float width = YGNodeLayoutGetWidth(YogaNode);
float height = YGNodeLayoutGetHeight(YogaNode);
float padding = YGNodeLayoutGetPadding(YogaNode, YGEdgeLeft);
float left = YGNodeLayoutGetLeft(YogaNode); //+ offset.x;
float top = YGNodeLayoutGetTop(YogaNode);// +offset.y;
float parentLeft = 0.0f;
float parentTop = 0.0f;
auto parent = YGNodeGetParent(YogaNode);
if (parent)
{
parentLeft = YGNodeLayoutGetLeft(YGNodeGetParent(YogaNode));
parentTop = YGNodeLayoutGetTop(YGNodeGetParent(YogaNode));
float parentPaddingTop = YGNodeLayoutGetPadding(parent, YGEdgeTop);
float parentPaddingLeft = YGNodeLayoutGetPadding(parent, YGEdgeTop);
// Overflow hidden.
float parentwidth = YGNodeLayoutGetWidth(parent);
if (parentwidth - YGNodeLayoutGetMargin(YogaNode, YGEdgeLeft) < width)
width = parentwidth - parentPaddingLeft;
float parentHeight = YGNodeLayoutGetHeight(parent);
if (parentHeight < height)
height = parentHeight - parentPaddingTop;
}
left += parentLeft;
top += parentTop;
return position.x > left && position.x < left + width && position.y > top && position.y < top + height;
}
}

View File

@@ -6,413 +6,415 @@
#include "../Core/Logger.h"
#include <src/UI/Styling/Style.h>
namespace Layout
namespace Nuake
{
enum class LayoutDirection
namespace Layout
{
LTR = 2, RTL = 3
enum class LayoutDirection
{
LTR = 2, RTL = 3
};
enum class FlexWrap
{
NO_WRAP, WRAP, WRAP_REVERSED
};
enum class FlexDirection
{
ROW, COLUMN, ROW_REVERSED, COLUMN_REVERSED
};
enum class JustifyContent
{
FLEX_START, FLEX_END, CENTER, SPACE_BETWEEN, SPACE_AROUND, SPACE_EVENLY
};
enum class AlignItems
{
STRETCH, FLEX_START, FLEX_END, CENTER, BASELINE, AUTO,
};
enum class AlignContent
{
FLEX_START, FLEX_END, STRETCH, CENTER, SPACE_BETWEEN, SPACE_AROUND
};
enum class PositionType
{
STATIC, RELATIVE, ABSOLUTE
};
enum Unit
{
PIXEL, PERCENT, AUTO
};
struct LayoutUnit
{
float Value = 0.0f;
Unit Unit = Unit::PIXEL;
};
struct LayoutVec4
{
LayoutUnit Top = LayoutUnit{ 0, PIXEL };
LayoutUnit Bottom = LayoutUnit{ 0, PIXEL };
LayoutUnit Left = LayoutUnit{ 0, PIXEL };
LayoutUnit Right = LayoutUnit{ 0, PIXEL };
};
}
enum class NodeType
{
Normal,
Text
};
enum class FlexWrap
// Base UI node.
class Node
{
NO_WRAP, WRAP, WRAP_REVERSED
};
public:
int Depth;
Ref<Node> Root;
Ref<Node> Parent;
std::vector<std::string> Groups;
std::vector<Ref<Node>> Childrens = std::vector<Ref<Node>>();
enum class FlexDirection
{
ROW, COLUMN, ROW_REVERSED, COLUMN_REVERSED
};
std::string OnClickSignature = "";
enum class JustifyContent
{
FLEX_START, FLEX_END, CENTER, SPACE_BETWEEN, SPACE_AROUND, SPACE_EVENLY
};
NodeType Type = NodeType::Normal;
enum class AlignItems
{
STRETCH, FLEX_START, FLEX_END, CENTER, BASELINE, AUTO,
};
YGNodeRef YogaNode;
enum class AlignContent
{
FLEX_START, FLEX_END, STRETCH, CENTER, SPACE_BETWEEN, SPACE_AROUND
};
Ref<Style> style;
enum class PositionType
{
STATIC, RELATIVE, ABSOLUTE
};
Layout::PositionType PositionType;
Layout::LayoutVec4 Position;
Layout::LayoutUnit Width, MaxWidth, MinWidth;
Layout::LayoutUnit Height, MaxHeight, MinHeight;
Layout::LayoutVec4 Margin;
Layout::LayoutVec4 Padding;
Layout::LayoutVec4 Border;
Color BackgroundColor;
Layout::LayoutDirection Direction;
Layout::FlexDirection FlexDirection = Layout::FlexDirection::ROW;
Layout::FlexWrap FlexWrap;
float FlexGrow;
float FlexShrink;
float FlexBasis;
float AspectRatio;
Layout::JustifyContent JustifyContent;
Layout::AlignItems AlignItems;
Layout::AlignItems AlignSelf;
Layout::AlignContent AlignContent;
enum Unit
{
PIXEL, PERCENT, AUTO
};
Node();
struct LayoutUnit
{
float Value = 0.0f;
Unit Unit = Unit::PIXEL;
};
void ApplyStyle(Ref<StyleGroup> stylegroup);
struct LayoutVec4
{
LayoutUnit Top = LayoutUnit{ 0, PIXEL };
LayoutUnit Bottom = LayoutUnit{ 0, PIXEL };
LayoutUnit Left = LayoutUnit{ 0, PIXEL };
LayoutUnit Right = LayoutUnit{ 0, PIXEL };
bool IsPositionInside(Vector2 position);
void AddGroup(const std::string& group)
{
Groups.push_back(group);
}
bool IsInGroup(const std::string& group)
{
for (auto& g : Groups)
if (g == group) return true;
return false;
}
std::vector<std::string> GetGroups() const { return Groups; }
void SetMargin()
{
switch (Margin.Left.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetMargin(YogaNode, YGEdgeLeft, Margin.Left.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetMarginPercent(YogaNode, YGEdgeLeft, Margin.Left.Value);
break;
case Layout::Unit::AUTO:
YGNodeStyleSetMarginAuto(YogaNode, YGEdgeLeft);
break;
}
switch (Margin.Right.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetMargin(YogaNode, YGEdgeRight, Margin.Right.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetMarginPercent(YogaNode, YGEdgeRight, Margin.Right.Value);
break;
case Layout::Unit::AUTO:
YGNodeStyleSetMarginAuto(YogaNode, YGEdgeRight);
break;
}
switch (Margin.Top.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetMargin(YogaNode, YGEdgeTop, Margin.Top.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetMarginPercent(YogaNode, YGEdgeTop, Margin.Top.Value);
break;
case Layout::Unit::AUTO:
YGNodeStyleSetMarginAuto(YogaNode, YGEdgeTop);
break;
}
switch (Margin.Bottom.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetMargin(YogaNode, YGEdgeBottom, Margin.Bottom.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetMarginPercent(YogaNode, YGEdgeBottom, Margin.Bottom.Value);
break;
case Layout::Unit::AUTO:
YGNodeStyleSetMarginAuto(YogaNode, YGEdgeTop);
break;
}
}
void SetPadding()
{
switch (Padding.Left.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetPadding(YogaNode, YGEdgeLeft, Padding.Left.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetPaddingPercent(YogaNode, YGEdgeLeft, Padding.Left.Value);
break;
}
switch (Padding.Right.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetPadding(YogaNode, YGEdgeRight, Padding.Right.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetPaddingPercent(YogaNode, YGEdgeRight, Padding.Right.Value);
break;
}
switch (Padding.Top.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetPadding(YogaNode, YGEdgeTop, Padding.Top.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetPaddingPercent(YogaNode, YGEdgeTop, Padding.Top.Value);
break;
}
switch (Padding.Bottom.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetPadding(YogaNode, YGEdgeBottom, Padding.Bottom.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetPaddingPercent(YogaNode, YGEdgeBottom, Padding.Bottom.Value);
break;
}
}
void SetBorder()
{
switch (Border.Left.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetBorder(YogaNode, YGEdgeLeft, Border.Left.Value);
break;
}
switch (Border.Right.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetBorder(YogaNode, YGEdgeRight, Border.Right.Value);
break;
}
switch (Border.Top.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetBorder(YogaNode, YGEdgeTop, Border.Top.Value);
break;
}
switch (Border.Bottom.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetBorder(YogaNode, YGEdgeBottom, Border.Bottom.Value);
break;
}
}
void SetYogaLayout()
{
switch (Width.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetWidth(YogaNode, Width.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetWidthPercent(YogaNode, Width.Value);
break;
case Layout::Unit::AUTO:
YGNodeStyleSetWidthAuto(YogaNode);
break;
}
switch (Height.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetHeight(YogaNode, Height.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetHeightPercent(YogaNode, Height.Value);
break;
case Layout::Unit::AUTO:
YGNodeStyleSetHeightAuto(YogaNode);
break;
}
SetMargin();
SetPadding();
SetBorder();
if (FlexWrap == Layout::FlexWrap::WRAP)
YGNodeStyleSetFlexWrap(YogaNode, YGWrapWrap);
else if (FlexWrap == Layout::FlexWrap::NO_WRAP)
YGNodeStyleSetFlexWrap(YogaNode, YGWrapNoWrap);
else if (FlexWrap == Layout::FlexWrap::WRAP_REVERSED)
YGNodeStyleSetFlexWrap(YogaNode, YGWrapWrapReverse);
if (FlexDirection == Layout::FlexDirection::ROW)
YGNodeStyleSetFlexDirection(YogaNode, YGFlexDirectionRow);
else if (FlexDirection == Layout::FlexDirection::ROW_REVERSED)
YGNodeStyleSetFlexDirection(YogaNode, YGFlexDirectionRowReverse);
else if (FlexDirection == Layout::FlexDirection::COLUMN)
YGNodeStyleSetFlexDirection(YogaNode, YGFlexDirectionColumn);
else if (FlexDirection == Layout::FlexDirection::COLUMN_REVERSED)
YGNodeStyleSetFlexDirection(YogaNode, YGFlexDirectionColumnReverse);
if (JustifyContent == Layout::JustifyContent::FLEX_START)
YGNodeStyleSetJustifyContent(YogaNode, YGJustifyFlexStart);
else if (JustifyContent == Layout::JustifyContent::FLEX_END)
YGNodeStyleSetJustifyContent(YogaNode, YGJustifyFlexEnd);
else if (JustifyContent == Layout::JustifyContent::CENTER)
YGNodeStyleSetJustifyContent(YogaNode, YGJustifyCenter);
else if (JustifyContent == Layout::JustifyContent::SPACE_BETWEEN)
YGNodeStyleSetJustifyContent(YogaNode, YGJustifySpaceBetween);
else if (JustifyContent == Layout::JustifyContent::SPACE_AROUND)
YGNodeStyleSetJustifyContent(YogaNode, YGJustifySpaceAround);
else if (JustifyContent == Layout::JustifyContent::SPACE_EVENLY)
YGNodeStyleSetJustifyContent(YogaNode, YGJustifySpaceEvenly);
if (AlignItems == Layout::AlignItems::FLEX_START)
YGNodeStyleSetAlignItems(YogaNode, YGAlignFlexStart);
else if (AlignItems == Layout::AlignItems::FLEX_END)
YGNodeStyleSetAlignItems(YogaNode, YGAlignFlexEnd);
else if (AlignItems == Layout::AlignItems::CENTER)
YGNodeStyleSetAlignItems(YogaNode, YGAlignCenter);
else if (AlignItems == Layout::AlignItems::BASELINE)
YGNodeStyleSetAlignItems(YogaNode, YGAlignBaseline);
else if (AlignItems == Layout::AlignItems::STRETCH)
YGNodeStyleSetAlignItems(YogaNode, YGAlignStretch);
//else if (AlignItems == Layout::AlignItems::AUTO)
// YGNodeStyleSetAlignItems(YogaNode, YGAlignAuto);
if (AlignSelf == Layout::AlignItems::FLEX_START)
YGNodeStyleSetAlignSelf(YogaNode, YGAlignFlexStart);
else if (AlignSelf == Layout::AlignItems::FLEX_END)
YGNodeStyleSetAlignSelf(YogaNode, YGAlignFlexEnd);
else if (AlignSelf == Layout::AlignItems::CENTER)
YGNodeStyleSetAlignSelf(YogaNode, YGAlignCenter);
else if (AlignSelf == Layout::AlignItems::BASELINE)
YGNodeStyleSetAlignSelf(YogaNode, YGAlignBaseline);
else if (AlignSelf == Layout::AlignItems::STRETCH)
YGNodeStyleSetAlignSelf(YogaNode, YGAlignStretch);
else if (AlignSelf == Layout::AlignItems::AUTO)
YGNodeStyleSetAlignSelf(YogaNode, YGAlignAuto);
if (AlignContent == Layout::AlignContent::FLEX_START)
YGNodeStyleSetAlignContent(YogaNode, YGAlignFlexStart);
else if (AlignContent == Layout::AlignContent::FLEX_END)
YGNodeStyleSetAlignContent(YogaNode, YGAlignFlexEnd);
else if (AlignContent == Layout::AlignContent::CENTER)
YGNodeStyleSetAlignContent(YogaNode, YGAlignCenter);
else if (AlignContent == Layout::AlignContent::STRETCH)
YGNodeStyleSetAlignContent(YogaNode, YGAlignStretch);
else if (AlignContent == Layout::AlignContent::SPACE_BETWEEN)
YGNodeStyleSetAlignContent(YogaNode, YGAlignSpaceBetween);
else if (AlignContent == Layout::AlignContent::SPACE_AROUND)
YGNodeStyleSetAlignContent(YogaNode, YGAlignSpaceAround);
if (PositionType == Layout::PositionType::RELATIVE)
YGNodeStyleSetPositionType(YogaNode, YGPositionTypeRelative);
else if (PositionType == Layout::PositionType::ABSOLUTE)
YGNodeStyleSetPositionType(YogaNode, YGPositionTypeAbsolute);
}
void Draw(float z)
{
Renderer2D::UIShader->Bind();
Color color = this->BackgroundColor;
Renderer2D::UIShader->SetUniform4f("background_color",
color.r / 255.f,
color.g / 255.f,
color.b / 255.f,
color.a / 255.f);
// Get transform
Matrix4 transform = Matrix4(1.0f);
float width = YGNodeLayoutGetWidth(YogaNode);
float height = YGNodeLayoutGetHeight(YogaNode);
float padding = YGNodeLayoutGetPadding(YogaNode, YGEdgeLeft);
float left = YGNodeLayoutGetLeft(YogaNode); //+ offset.x;
float top = YGNodeLayoutGetTop(YogaNode);// +offset.y;
float parentLeft = 0.0f;
float parentTop = 0.0f;
auto parent = YGNodeGetParent(YogaNode);
if (parent)
{
parentLeft = YGNodeLayoutGetLeft(YGNodeGetParent(YogaNode));
parentTop = YGNodeLayoutGetTop(YGNodeGetParent(YogaNode));
float parentPaddingTop = YGNodeLayoutGetPadding(parent, YGEdgeTop);
float parentPaddingLeft = YGNodeLayoutGetPadding(parent, YGEdgeTop);
// Overflow hidden.
float parentwidth = YGNodeLayoutGetWidth(parent);
if (parentwidth - YGNodeLayoutGetMargin(YogaNode, YGEdgeLeft) < width)
width = parentwidth - parentPaddingLeft;
float parentHeight = YGNodeLayoutGetHeight(parent);
if (parentHeight < height)
height = parentHeight - YGNodeLayoutGetMargin(YogaNode, YGEdgeTop) - parentPaddingTop;
}
transform = glm::translate(transform, Vector3(left + parentLeft, top + parentTop, 0.f));
Vector3 scale = Vector3(width, height, 0);
transform = glm::scale(transform, scale);
//Logger::Log("Left: " + std::to_string(left) + " Top:" + std::to_string(top));
Renderer2D::UIShader->SetUniformMat4f("model", transform);
Renderer2D::UIShader->SetUniform1f("u_border_radius", 8.f);
Renderer2D::UIShader->SetUniform2f("u_size", width, height);
Renderer2D::DrawRect();
}
};
}
enum class NodeType
{
Normal,
Text
};
// Base UI node.
class Node
{
public:
int Depth;
Ref<Node> Root;
Ref<Node> Parent;
std::vector<std::string> Groups;
std::vector<Ref<Node>> Childrens = std::vector<Ref<Node>>();
std::string OnClickSignature = "";
NodeType Type = NodeType::Normal;
YGNodeRef YogaNode;
Ref<Style> style;
Layout::PositionType PositionType;
Layout::LayoutVec4 Position;
Layout::LayoutUnit Width, MaxWidth, MinWidth;
Layout::LayoutUnit Height, MaxHeight, MinHeight;
Layout::LayoutVec4 Margin;
Layout::LayoutVec4 Padding;
Layout::LayoutVec4 Border;
Color BackgroundColor;
Layout::LayoutDirection Direction;
Layout::FlexDirection FlexDirection = Layout::FlexDirection::ROW;
Layout::FlexWrap FlexWrap;
float FlexGrow;
float FlexShrink;
float FlexBasis;
float AspectRatio;
Layout::JustifyContent JustifyContent;
Layout::AlignItems AlignItems;
Layout::AlignItems AlignSelf;
Layout::AlignContent AlignContent;
Node();
void ApplyStyle(Ref<StyleGroup> stylegroup);
bool IsPositionInside(Vector2 position);
void AddGroup(const std::string& group)
{
Groups.push_back(group);
}
bool IsInGroup(const std::string& group)
{
for (auto& g : Groups)
if (g == group) return true;
return false;
}
std::vector<std::string> GetGroups() const { return Groups; }
void SetMargin()
{
switch (Margin.Left.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetMargin(YogaNode, YGEdgeLeft, Margin.Left.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetMarginPercent(YogaNode, YGEdgeLeft, Margin.Left.Value);
break;
case Layout::Unit::AUTO:
YGNodeStyleSetMarginAuto(YogaNode, YGEdgeLeft);
break;
}
switch (Margin.Right.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetMargin(YogaNode, YGEdgeRight, Margin.Right.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetMarginPercent(YogaNode, YGEdgeRight, Margin.Right.Value);
break;
case Layout::Unit::AUTO:
YGNodeStyleSetMarginAuto(YogaNode, YGEdgeRight);
break;
}
switch (Margin.Top.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetMargin(YogaNode, YGEdgeTop, Margin.Top.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetMarginPercent(YogaNode, YGEdgeTop, Margin.Top.Value);
break;
case Layout::Unit::AUTO:
YGNodeStyleSetMarginAuto(YogaNode, YGEdgeTop);
break;
}
switch (Margin.Bottom.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetMargin(YogaNode, YGEdgeBottom, Margin.Bottom.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetMarginPercent(YogaNode, YGEdgeBottom, Margin.Bottom.Value);
break;
case Layout::Unit::AUTO:
YGNodeStyleSetMarginAuto(YogaNode, YGEdgeTop);
break;
}
}
void SetPadding()
{
switch (Padding.Left.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetPadding(YogaNode, YGEdgeLeft, Padding.Left.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetPaddingPercent(YogaNode, YGEdgeLeft, Padding.Left.Value);
break;
}
switch (Padding.Right.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetPadding(YogaNode, YGEdgeRight, Padding.Right.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetPaddingPercent(YogaNode, YGEdgeRight, Padding.Right.Value);
break;
}
switch (Padding.Top.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetPadding(YogaNode, YGEdgeTop, Padding.Top.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetPaddingPercent(YogaNode, YGEdgeTop, Padding.Top.Value);
break;
}
switch (Padding.Bottom.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetPadding(YogaNode, YGEdgeBottom, Padding.Bottom.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetPaddingPercent(YogaNode, YGEdgeBottom, Padding.Bottom.Value);
break;
}
}
void SetBorder()
{
switch (Border.Left.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetBorder(YogaNode, YGEdgeLeft, Border.Left.Value);
break;
}
switch (Border.Right.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetBorder(YogaNode, YGEdgeRight, Border.Right.Value);
break;
}
switch (Border.Top.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetBorder(YogaNode, YGEdgeTop, Border.Top.Value);
break;
}
switch (Border.Bottom.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetBorder(YogaNode, YGEdgeBottom, Border.Bottom.Value);
break;
}
}
void SetYogaLayout()
{
switch (Width.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetWidth(YogaNode, Width.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetWidthPercent(YogaNode, Width.Value);
break;
case Layout::Unit::AUTO:
YGNodeStyleSetWidthAuto(YogaNode);
break;
}
switch (Height.Unit)
{
case Layout::Unit::PIXEL:
YGNodeStyleSetHeight(YogaNode, Height.Value);
break;
case Layout::Unit::PERCENT:
YGNodeStyleSetHeightPercent(YogaNode, Height.Value);
break;
case Layout::Unit::AUTO:
YGNodeStyleSetHeightAuto(YogaNode);
break;
}
SetMargin();
SetPadding();
SetBorder();
if(FlexWrap == Layout::FlexWrap::WRAP)
YGNodeStyleSetFlexWrap(YogaNode, YGWrapWrap);
else if (FlexWrap == Layout::FlexWrap::NO_WRAP)
YGNodeStyleSetFlexWrap(YogaNode, YGWrapNoWrap);
else if (FlexWrap == Layout::FlexWrap::WRAP_REVERSED)
YGNodeStyleSetFlexWrap(YogaNode, YGWrapWrapReverse);
if(FlexDirection == Layout::FlexDirection::ROW)
YGNodeStyleSetFlexDirection(YogaNode, YGFlexDirectionRow);
else if (FlexDirection == Layout::FlexDirection::ROW_REVERSED)
YGNodeStyleSetFlexDirection(YogaNode, YGFlexDirectionRowReverse);
else if (FlexDirection == Layout::FlexDirection::COLUMN)
YGNodeStyleSetFlexDirection(YogaNode, YGFlexDirectionColumn);
else if (FlexDirection == Layout::FlexDirection::COLUMN_REVERSED)
YGNodeStyleSetFlexDirection(YogaNode, YGFlexDirectionColumnReverse);
if(JustifyContent == Layout::JustifyContent::FLEX_START)
YGNodeStyleSetJustifyContent(YogaNode, YGJustifyFlexStart);
else if (JustifyContent == Layout::JustifyContent::FLEX_END)
YGNodeStyleSetJustifyContent(YogaNode, YGJustifyFlexEnd);
else if (JustifyContent == Layout::JustifyContent::CENTER)
YGNodeStyleSetJustifyContent(YogaNode, YGJustifyCenter);
else if (JustifyContent == Layout::JustifyContent::SPACE_BETWEEN)
YGNodeStyleSetJustifyContent(YogaNode, YGJustifySpaceBetween);
else if (JustifyContent == Layout::JustifyContent::SPACE_AROUND)
YGNodeStyleSetJustifyContent(YogaNode, YGJustifySpaceAround);
else if (JustifyContent == Layout::JustifyContent::SPACE_EVENLY)
YGNodeStyleSetJustifyContent(YogaNode, YGJustifySpaceEvenly);
if (AlignItems == Layout::AlignItems::FLEX_START)
YGNodeStyleSetAlignItems(YogaNode, YGAlignFlexStart);
else if (AlignItems == Layout::AlignItems::FLEX_END)
YGNodeStyleSetAlignItems(YogaNode, YGAlignFlexEnd);
else if (AlignItems == Layout::AlignItems::CENTER)
YGNodeStyleSetAlignItems(YogaNode, YGAlignCenter);
else if (AlignItems == Layout::AlignItems::BASELINE)
YGNodeStyleSetAlignItems(YogaNode, YGAlignBaseline);
else if (AlignItems == Layout::AlignItems::STRETCH)
YGNodeStyleSetAlignItems(YogaNode, YGAlignStretch);
//else if (AlignItems == Layout::AlignItems::AUTO)
// YGNodeStyleSetAlignItems(YogaNode, YGAlignAuto);
if (AlignSelf == Layout::AlignItems::FLEX_START)
YGNodeStyleSetAlignSelf(YogaNode, YGAlignFlexStart);
else if (AlignSelf == Layout::AlignItems::FLEX_END)
YGNodeStyleSetAlignSelf(YogaNode, YGAlignFlexEnd);
else if (AlignSelf == Layout::AlignItems::CENTER)
YGNodeStyleSetAlignSelf(YogaNode, YGAlignCenter);
else if (AlignSelf == Layout::AlignItems::BASELINE)
YGNodeStyleSetAlignSelf(YogaNode, YGAlignBaseline);
else if (AlignSelf == Layout::AlignItems::STRETCH)
YGNodeStyleSetAlignSelf(YogaNode, YGAlignStretch);
else if (AlignSelf == Layout::AlignItems::AUTO)
YGNodeStyleSetAlignSelf(YogaNode, YGAlignAuto);
if (AlignContent == Layout::AlignContent::FLEX_START)
YGNodeStyleSetAlignContent(YogaNode, YGAlignFlexStart);
else if (AlignContent == Layout::AlignContent::FLEX_END)
YGNodeStyleSetAlignContent(YogaNode, YGAlignFlexEnd);
else if (AlignContent == Layout::AlignContent::CENTER)
YGNodeStyleSetAlignContent(YogaNode, YGAlignCenter);
else if (AlignContent == Layout::AlignContent::STRETCH)
YGNodeStyleSetAlignContent(YogaNode, YGAlignStretch);
else if (AlignContent == Layout::AlignContent::SPACE_BETWEEN)
YGNodeStyleSetAlignContent(YogaNode, YGAlignSpaceBetween);
else if (AlignContent == Layout::AlignContent::SPACE_AROUND)
YGNodeStyleSetAlignContent(YogaNode, YGAlignSpaceAround);
if (PositionType == Layout::PositionType::RELATIVE)
YGNodeStyleSetPositionType(YogaNode, YGPositionTypeRelative);
else if (PositionType == Layout::PositionType::ABSOLUTE)
YGNodeStyleSetPositionType(YogaNode, YGPositionTypeAbsolute);
}
void Draw(float z)
{
Renderer2D::UIShader->Bind();
Color color = this->BackgroundColor;
Renderer2D::UIShader->SetUniform4f("background_color",
color.r / 255.f,
color.g / 255.f,
color.b / 255.f,
color.a / 255.f);
// Get transform
Matrix4 transform = Matrix4(1.0f);
float width = YGNodeLayoutGetWidth(YogaNode);
float height = YGNodeLayoutGetHeight(YogaNode);
float padding = YGNodeLayoutGetPadding(YogaNode, YGEdgeLeft);
float left = YGNodeLayoutGetLeft(YogaNode); //+ offset.x;
float top = YGNodeLayoutGetTop(YogaNode);// +offset.y;
float parentLeft = 0.0f;
float parentTop = 0.0f;
auto parent = YGNodeGetParent(YogaNode);
if (parent)
{
parentLeft = YGNodeLayoutGetLeft(YGNodeGetParent(YogaNode));
parentTop = YGNodeLayoutGetTop(YGNodeGetParent(YogaNode));
float parentPaddingTop = YGNodeLayoutGetPadding(parent, YGEdgeTop);
float parentPaddingLeft = YGNodeLayoutGetPadding(parent, YGEdgeTop);
// Overflow hidden.
float parentwidth = YGNodeLayoutGetWidth(parent);
if (parentwidth - YGNodeLayoutGetMargin(YogaNode, YGEdgeLeft) < width )
width = parentwidth - parentPaddingLeft;
float parentHeight = YGNodeLayoutGetHeight(parent);
if (parentHeight < height)
height = parentHeight - YGNodeLayoutGetMargin(YogaNode, YGEdgeTop) - parentPaddingTop;
}
transform = glm::translate(transform, Vector3(left + parentLeft, top + parentTop, 0.f));
Vector3 scale = Vector3(width, height, 0);
transform = glm::scale(transform, scale);
//Logger::Log("Left: " + std::to_string(left) + " Top:" + std::to_string(top));
Renderer2D::UIShader->SetUniformMat4f("model", transform);
Renderer2D::UIShader->SetUniform1f("u_border_radius", 8.f);
Renderer2D::UIShader->SetUniform2f("u_size", width, height);
Renderer2D::DrawRect();
}
};

View File

@@ -6,104 +6,106 @@
#include <src/Rendering/Shaders/Shader.h>
#include <src/Rendering/Renderer2D.h>
namespace UI
namespace Nuake
{
// Styling props
class RectProp
namespace UI
{
public:
float BorderRadius = 0.0f;
float BorderMinXWidth = 0.0f;
float BorderMinYWidth = 0.0f;
float BorderMaxXWidth = 0.0f;
float BorderMaxYWidth = 0.0f;
Color BorderColor = Color(0, 0, 0, 1);
Color BackgroundColor = Color(1, 0, 0, 1);
Ref<Texture> BackgroundTexture;
};
// This is the base component for every UI layout.
class Rect
{
private:
std::string id; // This is similar to html ids
std::vector<std::string> groups; // this is similar to html classes
public:
RectProp Props;
float MinX;
float MinY;
float MaxX;
float MaxY;
static Ref<Rect> New(float minx, float miny, float maxx, float maxy)
// Styling props
class RectProp
{
return CreateRef<Rect>(minx, miny, maxx, maxy);
}
public:
float BorderRadius = 0.0f;
float BorderMinXWidth = 0.0f;
float BorderMinYWidth = 0.0f;
float BorderMaxXWidth = 0.0f;
float BorderMaxYWidth = 0.0f;
Color BorderColor = Color(0, 0, 0, 1);
Color BackgroundColor = Color(1, 0, 0, 1);
Ref<Texture> BackgroundTexture;
};
Rect(float minx, float miny, float maxx, float maxy)
// This is the base component for every UI layout.
class Rect
{
this->MinX = minx;
this->MinY = miny;
this->MaxX = maxx;
this->MaxY = maxy;
private:
std::string id; // This is similar to html ids
std::vector<std::string> groups; // this is similar to html classes
this->id = "";
this->groups = std::vector<std::string>();
}
public:
RectProp Props;
// Check if a point is inside the rectangle.
bool IsInside(Vector2 point)
{
return point.x > MinX && point.x < MaxX && point.y > MinY && point.y < MaxY;
}
float MinX;
float MinY;
float MaxX;
float MaxY;
bool HasGroup(const std::string& group)
{
for (auto g : groups)
if (g == group)
return true;
return false;
}
static Ref<Rect> New(float minx, float miny, float maxx, float maxy)
{
return CreateRef<Rect>(minx, miny, maxx, maxy);
}
std::vector<std::string> GetGroups() { return groups; }
void AddGroup(const std::string& group)
{
// Check if already has group.
for (auto g : groups)
if (g == group)
return;
groups.push_back(group);
}
Rect(float minx, float miny, float maxx, float maxy)
{
this->MinX = minx;
this->MinY = miny;
this->MaxX = maxx;
this->MaxY = maxy;
std::string GetID() { return id; }
void SetID(const std::string& id) { this->id = id; }
this->id = "";
this->groups = std::vector<std::string>();
}
// Cuts a rectangle left and returns a new one.
Ref<Rect> CutLeft(float a)
{
float minx = this->MinX;
this->MinX = std::min(this->MaxX, this->MinX + a);
return CreateRef<Rect>(minx, this->MinY, this->MinX, this->MaxY);
}
// Check if a point is inside the rectangle.
bool IsInside(Vector2 point)
{
return point.x > MinX && point.x < MaxX&& point.y > MinY && point.y < MaxY;
}
void Draw()
{
Renderer2D::UIShader->SetUniform4f("background_color", Props.BackgroundColor.r,
Props.BackgroundColor.g,
Props.BackgroundColor.b,
Props.BackgroundColor.a);
bool HasGroup(const std::string& group)
{
for (auto g : groups)
if (g == group)
return true;
return false;
}
// Get transform
Matrix4 transform = Matrix4(1.0f);
transform = glm::translate(transform, Vector3(MinX, MinY, 0));
Vector3 scale = Vector3(MaxX - MinX, MaxY - MinY, 0);
transform = glm::scale(transform, scale);
Renderer2D::UIShader->SetUniformMat4f("model", transform);
std::vector<std::string> GetGroups() { return groups; }
void AddGroup(const std::string& group)
{
// Check if already has group.
for (auto g : groups)
if (g == group)
return;
groups.push_back(group);
}
Renderer2D::DrawRect();
}
};
}
std::string GetID() { return id; }
void SetID(const std::string& id) { this->id = id; }
// Cuts a rectangle left and returns a new one.
Ref<Rect> CutLeft(float a)
{
float minx = this->MinX;
this->MinX = std::min(this->MaxX, this->MinX + a);
return CreateRef<Rect>(minx, this->MinY, this->MinX, this->MaxY);
}
void Draw()
{
Renderer2D::UIShader->SetUniform4f("background_color", Props.BackgroundColor.r,
Props.BackgroundColor.g,
Props.BackgroundColor.b,
Props.BackgroundColor.a);
// Get transform
Matrix4 transform = Matrix4(1.0f);
transform = glm::translate(transform, Vector3(MinX, MinY, 0));
Vector3 scale = Vector3(MaxX - MinX, MaxY - MinY, 0);
transform = glm::scale(transform, scale);
Renderer2D::UIShader->SetUniformMat4f("model", transform);
Renderer2D::DrawRect();
}
};
}
}

View File

@@ -1,67 +1,69 @@
#pragma once
#include "Node.h"
struct TextStyle
namespace Nuake
{
Ref<Font> font;
float fontSize;
Color color;
};
class TextNode : public Node
{
public:
std::string content = "Hello World!";
TextStyle style;
void SetTextStyle(TextStyle textStyle)
struct TextStyle
{
this->style = textStyle;
}
Ref<Font> font;
float fontSize;
Color color;
};
void CalculateSize()
class TextNode : public Node
{
}
public:
std::string content = "Hello World!";
TextStyle style;
void Draw(float z)
{
Renderer2D::TextShader->Bind();
Matrix4 transform = Matrix4(1.0f);
float width = YGNodeLayoutGetWidth(this->YogaNode);
float height = YGNodeLayoutGetHeight(this->YogaNode);
float left = YGNodeLayoutGetLeft(this->YogaNode); //+ offset.x;
float top = YGNodeLayoutGetTop(this->YogaNode);// +offset.y;
float parentLeft = 0.0f;
float parentTop = 0.0f;
auto parent = YGNodeGetParent(this->YogaNode);
if (parent)
void SetTextStyle(TextStyle textStyle)
{
//parentLeft = YGNodeLayoutGetLeft(YGNodeGetParent(this->YogaNode));
//parentTop = YGNodeLayoutGetTop(YGNodeGetParent(this->YogaNode));
//float parentPaddingTop = YGNodeLayoutGetPadding(parent, YGEdgeTop);
//float parentPaddingLeft = YGNodeLayoutGetPadding(parent, YGEdgeTop);
//// Overflow hidden.
//float parentwidth = YGNodeLayoutGetWidth(parent);
//if (parentwidth - YGNodeLayoutGetMargin(this->YogaNode, YGEdgeLeft) < width)
// width = parentwidth - parentPaddingLeft;
//float parentHeight = YGNodeLayoutGetHeight(parent);
//if (parentHeight < height)
// height = parentHeight - YGNodeLayoutGetMargin(this->YogaNode, YGEdgeTop) - parentPaddingTop;
this->style = textStyle;
}
void CalculateSize()
{
}
void Draw(float z)
{
Renderer2D::TextShader->Bind();
Matrix4 transform = Matrix4(1.0f);
float width = YGNodeLayoutGetWidth(this->YogaNode);
float height = YGNodeLayoutGetHeight(this->YogaNode);
float left = YGNodeLayoutGetLeft(this->YogaNode); //+ offset.x;
float top = YGNodeLayoutGetTop(this->YogaNode);// +offset.y;
float parentLeft = 0.0f;
float parentTop = 0.0f;
auto parent = YGNodeGetParent(this->YogaNode);
if (parent)
{
//parentLeft = YGNodeLayoutGetLeft(YGNodeGetParent(this->YogaNode));
//parentTop = YGNodeLayoutGetTop(YGNodeGetParent(this->YogaNode));
//float parentPaddingTop = YGNodeLayoutGetPadding(parent, YGEdgeTop);
//float parentPaddingLeft = YGNodeLayoutGetPadding(parent, YGEdgeTop);
//// Overflow hidden.
//float parentwidth = YGNodeLayoutGetWidth(parent);
//if (parentwidth - YGNodeLayoutGetMargin(this->YogaNode, YGEdgeLeft) < width)
// width = parentwidth - parentPaddingLeft;
//float parentHeight = YGNodeLayoutGetHeight(parent);
//if (parentHeight < height)
// height = parentHeight - YGNodeLayoutGetMargin(this->YogaNode, YGEdgeTop) - parentPaddingTop;
}
transform = glm::translate(transform, Vector3(left + parentLeft, top + parentTop, 0.f));
transform = glm::translate(transform, Vector3(left + parentLeft, top + parentTop, 0.f));
//Logger::Log("Left: " + std::to_string(left) + " Top:" + std::to_string(top));
//Logger::Log("Left: " + std::to_string(left) + " Top:" + std::to_string(top));
Renderer2D::DrawString(content, style, transform);
//Renderer2D::DrawString(content, style.font, Vector2(Position.Left, Position.Top), 2.0);
}
};
Renderer2D::DrawString(content, style, transform);
//Renderer2D::DrawString(content, style.font, Vector2(Position.Left, Position.Top), 2.0);
}
};
}

View File

@@ -1,84 +1,88 @@
#pragma once
#include "../Core/Maths.h"
#include <map>
enum class PropType
namespace Nuake
{
HEIGHT, MAX_HEIGHT, MIN_HEIGHT, WIDTH, MAX_WIDTH, MIN_WIDTH,
LAYOUT_DIRECTION, JUSTIFY_CONTENT,
FLEX_BASIS, FLEX_GROW, FLEX_SHRINK,FLEX_WRAP, FLEX_DIRECTION,
ASPECT_RATIO,
ALIGN_ITEMS, SELF_ALIGN, ALIGN_CONTENT,
POSITION,
LEFT, RIGHT, TOP, BOTTOM,
MARGIN, MARGIN_LEFT, MARGIN_RIGHT, MARGIN_TOP, MARGIN_BOTTOM,
PADDING, PADDING_LEFT, PADDING_RIGHT, PADDING_TOP, PADDING_BOTTOM,
BORDER, BORDER_LEFT, BORDER_RIGHT, BORDER_TOP, BORDER_BOTTOM,
BORDER_RADIUS, BORDER_RADIUS_LEFT, BORDER_RADIUS_RIGHT, BORDER_RADIUS_TOP, BORDER_RADIUS_BOTTOM,
BACKGROUND_COLOR, COLOR,
};
enum class PropValueType
{
PIXEL, PERCENT, AUTO, COLOR, ENUM
};
union Value
{
float Number;
Color Color;
int Enum;
};
struct PropValue
{
PropValueType type;
Value value;
};
class StyleGroup
{
public:
std::map<PropType, PropValue> Props;
StyleGroup()
enum class PropType
{
this->Props = std::map<PropType, PropValue>();
}
HEIGHT, MAX_HEIGHT, MIN_HEIGHT, WIDTH, MAX_WIDTH, MIN_WIDTH,
LAYOUT_DIRECTION, JUSTIFY_CONTENT,
FLEX_BASIS, FLEX_GROW, FLEX_SHRINK, FLEX_WRAP, FLEX_DIRECTION,
ASPECT_RATIO,
ALIGN_ITEMS, SELF_ALIGN, ALIGN_CONTENT,
POSITION,
LEFT, RIGHT, TOP, BOTTOM,
MARGIN, MARGIN_LEFT, MARGIN_RIGHT, MARGIN_TOP, MARGIN_BOTTOM,
PADDING, PADDING_LEFT, PADDING_RIGHT, PADDING_TOP, PADDING_BOTTOM,
BORDER, BORDER_LEFT, BORDER_RIGHT, BORDER_TOP, BORDER_BOTTOM,
BORDER_RADIUS, BORDER_RADIUS_LEFT, BORDER_RADIUS_RIGHT, BORDER_RADIUS_TOP, BORDER_RADIUS_BOTTOM,
BACKGROUND_COLOR, COLOR,
};
void SetProp(PropType type, PropValue prop)
enum class PropValueType
{
Props[type] = prop;
}
PropValue& GetProp(PropType type)
PIXEL, PERCENT, AUTO, COLOR, ENUM
};
union Value
{
if (Props.find(type) != Props.end())
return Props[type];
return PropValue();
}
bool HasProp(PropType type)
float Number;
Color Color;
int Enum;
};
struct PropValue
{
return Props.find(type) != Props.end();
}
PropValueType type;
Value value;
};
std::map<PropType, PropValue> GetProps()
class StyleGroup
{
return Props;
}
public:
std::map<PropType, PropValue> Props;
StyleGroup operator+(StyleGroup other)
{
for (auto p : other.Props)
StyleGroup()
{
this->Props[p.first] = p.second;
this->Props = std::map<PropType, PropValue>();
}
return *this;
}
};
void SetProp(PropType type, PropValue prop)
{
Props[type] = prop;
}
PropValue& GetProp(PropType type)
{
if (Props.find(type) != Props.end())
return Props[type];
return PropValue();
}
bool HasProp(PropType type)
{
return Props.find(type) != Props.end();
}
std::map<PropType, PropValue> GetProps()
{
return Props;
}
StyleGroup operator+(StyleGroup other)
{
for (auto p : other.Props)
{
this->Props[p.first] = p.second;
}
return *this;
}
};
class Style
{
class Style
{
};
};
}

View File

@@ -2,52 +2,53 @@
#include <regex>
#include <src/Vendors/pugixml/pugixml.hpp>
PropValue StyleSheetParser::ParsePropType(const std::string& str, PropType type)
namespace Nuake
{
switch (type)
PropValue StyleSheetParser::ParsePropType(const std::string& str, PropType type)
{
case PropType::HEIGHT: case PropType::MIN_HEIGHT: case PropType::MAX_HEIGHT:
case PropType::WIDTH: case PropType::MIN_WIDTH: case PropType::MAX_WIDTH:
case PropType::LEFT: case PropType::RIGHT: case PropType::TOP: case PropType::BOTTOM:
case PropType::MARGIN_LEFT: case PropType::MARGIN_RIGHT: case PropType::MARGIN_TOP: case PropType::MARGIN_BOTTOM:
case PropType::PADDING_LEFT: case PropType::PADDING_RIGHT: case PropType::PADDING_TOP: case PropType::PADDING_BOTTOM:
case PropType::BORDER_LEFT: case PropType::BORDER_RIGHT: case PropType::BORDER_TOP: case PropType::BORDER_BOTTOM:
{
std::regex only_number("[0-9]+");
std::regex not_number("[^0-9]+");
// is percentage
std::smatch match_value;
if (std::regex_search(str.begin(), str.end(), match_value, only_number))
switch (type)
{
std::smatch match_type;
if (std::regex_search(str.begin(), str.end(), match_type, not_number))
case PropType::HEIGHT: case PropType::MIN_HEIGHT: case PropType::MAX_HEIGHT:
case PropType::WIDTH: case PropType::MIN_WIDTH: case PropType::MAX_WIDTH:
case PropType::LEFT: case PropType::RIGHT: case PropType::TOP: case PropType::BOTTOM:
case PropType::MARGIN_LEFT: case PropType::MARGIN_RIGHT: case PropType::MARGIN_TOP: case PropType::MARGIN_BOTTOM:
case PropType::PADDING_LEFT: case PropType::PADDING_RIGHT: case PropType::PADDING_TOP: case PropType::PADDING_BOTTOM:
case PropType::BORDER_LEFT: case PropType::BORDER_RIGHT: case PropType::BORDER_TOP: case PropType::BORDER_BOTTOM:
{
std::regex only_number("[0-9]+");
std::regex not_number("[^0-9]+");
// is percentage
std::smatch match_value;
if (std::regex_search(str.begin(), str.end(), match_value, only_number))
{
float value = std::stof(match_value[0]);
if (match_type[0] == "%")
std::smatch match_type;
if (std::regex_search(str.begin(), str.end(), match_type, not_number))
{
PropValue returnValue = PropValue{
PropValueType::PERCENT,
{0}
};
returnValue.value.Number = value;
return returnValue;
}
else if (match_type[0] == "px")
{
PropValue returnValue = PropValue{
PropValueType::PIXEL,
{0}
};
returnValue.value.Number = value;
return returnValue;
float value = std::stof(match_value[0]);
if (match_type[0] == "%")
{
PropValue returnValue = PropValue{
PropValueType::PERCENT,
{0}
};
returnValue.value.Number = value;
return returnValue;
}
else if (match_type[0] == "px")
{
PropValue returnValue = PropValue {
PropValueType::PIXEL,
{0}
};
returnValue.value.Number = value;
return returnValue;
}
}
}
}
}
break;
break;
}
return PropValue();
}
return PropValue();
}

View File

@@ -2,9 +2,12 @@
#include <string>
#include "Style.h"
class StyleSheetParser
namespace Nuake
{
class StyleSheetParser
{
public:
static PropValue ParsePropType(const std::string& str, PropType type);
};
public:
static PropValue ParsePropType(const std::string& str, PropType type);
};
}

View File

@@ -1,15 +1,10 @@
#include "Stylesheet.h"
namespace UI
{
Ref<StyleSheet> StyleSheet::New(const std::string& path)
{
return CreateRef<StyleSheet>(path);
namespace Nuake {
namespace UI {
Ref<StyleSheet> StyleSheet::New(const std::string& path)
{
return CreateRef<StyleSheet>(path);
}
}
}

View File

@@ -9,252 +9,256 @@
#include <regex>
#include <string>
#include <map>
namespace UI
namespace Nuake
{
class StyleSheet
namespace UI
{
private:
KatanaOutput* Data;
std::map<std::string, Ref<StyleGroup>> Styles;
public:
std::string Path;
static Ref<StyleSheet> New(const std::string& path);
std::vector<std::string> Split(std::string const& str, const char delim)
class StyleSheet
{
std::vector<std::string> result;
size_t start;
size_t end = 0;
private:
KatanaOutput* Data;
while ((start = str.find_first_not_of(delim, end)) != std::string::npos)
std::map<std::string, Ref<StyleGroup>> Styles;
public:
std::string Path;
static Ref<StyleSheet> New(const std::string& path);
std::vector<std::string> Split(std::string const& str, const char delim)
{
end = str.find(delim, start);
result.push_back(str.substr(start, end - start));
}
std::vector<std::string> result;
size_t start;
size_t end = 0;
return result;
}
void AddStyleGroup(std::string selector, Ref<StyleGroup> group)
{
Styles[selector] = group;
}
bool HasStyleGroup(const std::string& group)
{
return Styles.find(group) != Styles.end();
}
Ref<StyleGroup> GetStyleGroup(const std::string group)
{
if (!HasStyleGroup(group))
return nullptr;
return Styles[group];
}
StyleSheet(const std::string& path)
{
this->Path = path;
ParseSheet();
}
~StyleSheet()
{
katana_destroy_output(Data);
}
bool ParseRule(KatanaRule* rule)
{
if (rule->type == KatanaRuleStyle)
{
Ref<StyleGroup> styleGroup = CreateRef<StyleGroup>();
// Selectors
KatanaStyleRule* stylerule = (KatanaStyleRule*)rule;
for (int j = 0; j < stylerule->selectors->length; j++)
while ((start = str.find_first_not_of(delim, end)) != std::string::npos)
{
KatanaSelector* selector = (KatanaSelector*)stylerule->selectors->data[j];
std::string name = selector->data->value;
AddStyleGroup(name, styleGroup);
end = str.find(delim, start);
result.push_back(str.substr(start, end - start));
}
// Declarations
for (int k = 0; k < stylerule->declarations->length; k++)
return result;
}
void AddStyleGroup(std::string selector, Ref<StyleGroup> group)
{
Styles[selector] = group;
}
bool HasStyleGroup(const std::string& group)
{
return Styles.find(group) != Styles.end();
}
Ref<StyleGroup> GetStyleGroup(const std::string group)
{
if (!HasStyleGroup(group))
return nullptr;
return Styles[group];
}
StyleSheet(const std::string& path)
{
this->Path = path;
ParseSheet();
}
~StyleSheet()
{
katana_destroy_output(Data);
}
bool ParseRule(KatanaRule* rule)
{
if (rule->type == KatanaRuleStyle)
{
KatanaDeclaration* declaration = (KatanaDeclaration*)(stylerule->declarations->data[k]);
std::string value = declaration->raw;
std::string name = declaration->property;
PropType type;
Ref<StyleGroup> styleGroup = CreateRef<StyleGroup>();
if (name == "height") type = PropType::HEIGHT;
if (name == "width") type = PropType::WIDTH;
if (name == "left") type = PropType::LEFT;
if (name == "right") type = PropType::RIGHT;
if (name == "top") type = PropType::TOP;
if (name == "bottom") type = PropType::BOTTOM;
if (name == "margin")
// Selectors
KatanaStyleRule* stylerule = (KatanaStyleRule*)rule;
for (int j = 0; j < stylerule->selectors->length; j++)
{
std::regex regex("[0-9]+[^ ]+");
std::smatch match_value;
Layout::LayoutVec4 result;
KatanaSelector* selector = (KatanaSelector*)stylerule->selectors->data[j];
std::string name = selector->data->value;
std::vector<std::string> splits = Split(value, ' ');
int idx = 0;
for (auto& s : splits)
AddStyleGroup(name, styleGroup);
}
// Declarations
for (int k = 0; k < stylerule->declarations->length; k++)
{
KatanaDeclaration* declaration = (KatanaDeclaration*)(stylerule->declarations->data[k]);
std::string value = declaration->raw;
std::string name = declaration->property;
PropType type;
if (name == "height") type = PropType::HEIGHT;
if (name == "width") type = PropType::WIDTH;
if (name == "left") type = PropType::LEFT;
if (name == "right") type = PropType::RIGHT;
if (name == "top") type = PropType::TOP;
if (name == "bottom") type = PropType::BOTTOM;
if (name == "margin")
{
if (idx == 0)
std::regex regex("[0-9]+[^ ]+");
std::smatch match_value;
Layout::LayoutVec4 result;
std::vector<std::string> splits = Split(value, ' ');
int idx = 0;
for (auto& s : splits)
{
type = PropType::MARGIN_LEFT;
styleGroup->SetProp(type, StyleSheetParser::ParsePropType(s, type));
if (idx == 0)
{
type = PropType::MARGIN_LEFT;
styleGroup->SetProp(type, StyleSheetParser::ParsePropType(s, type));
}
else if (idx == 1)
{
type = PropType::MARGIN_RIGHT;
styleGroup->SetProp(type, StyleSheetParser::ParsePropType(s, type));
}
else if (idx == 2)
{
type = PropType::MARGIN_TOP;
styleGroup->SetProp(type, StyleSheetParser::ParsePropType(s, type));
}
else if (idx == 3)
{
type = PropType::MARGIN_BOTTOM;
styleGroup->SetProp(type, StyleSheetParser::ParsePropType(s, type));
}
idx++;
}
else if (idx == 1)
{
type = PropType::MARGIN_RIGHT;
styleGroup->SetProp(type, StyleSheetParser::ParsePropType(s, type));
}
else if (idx == 2)
{
type = PropType::MARGIN_TOP;
styleGroup->SetProp(type, StyleSheetParser::ParsePropType(s, type));
}
else if (idx == 3)
{
type = PropType::MARGIN_BOTTOM;
styleGroup->SetProp(type, StyleSheetParser::ParsePropType(s, type));
}
idx++;
continue;
}
continue;
}
if (name == "flex-direction")
{
type = PropType::FLEX_DIRECTION;
Value propValue{};
if (value == "row")
propValue.Enum = (int)Layout::FlexDirection::ROW;
if (value == "row-reversed")
propValue.Enum = (int)Layout::FlexDirection::ROW_REVERSED;
if (value == "column")
propValue.Enum = (int)Layout::FlexDirection::COLUMN;
if (value == "column-reversed")
propValue.Enum = (int)Layout::FlexDirection::COLUMN_REVERSED;
if (name == "flex-direction")
{
type = PropType::FLEX_DIRECTION;
Value propValue{};
styleGroup->SetProp(type, PropValue{ PropValueType::ENUM, propValue });
continue;
}
if (name == "justify-content")
{
type = PropType::JUSTIFY_CONTENT;
Value propValue{};
if (value == "flex-start")
propValue.Enum = (int)Layout::JustifyContent::FLEX_START;
if (value == "flex-end")
propValue.Enum = (int)Layout::JustifyContent::FLEX_END;
if (value == "center")
propValue.Enum = (int)Layout::JustifyContent::CENTER;
if (value == "space-between")
propValue.Enum = (int)Layout::JustifyContent::SPACE_BETWEEN;
if (value == "space-around")
propValue.Enum = (int)Layout::JustifyContent::SPACE_AROUND;
if (value == "space-evenly")
propValue.Enum = (int)Layout::JustifyContent::SPACE_EVENLY;
if (value == "row")
propValue.Enum = (int)Layout::FlexDirection::ROW;
if (value == "row-reversed")
propValue.Enum = (int)Layout::FlexDirection::ROW_REVERSED;
if (value == "column")
propValue.Enum = (int)Layout::FlexDirection::COLUMN;
if (value == "column-reversed")
propValue.Enum = (int)Layout::FlexDirection::COLUMN_REVERSED;
styleGroup->SetProp(type, PropValue{ PropValueType::ENUM, propValue });
continue;
}
if (name == "flex-wrap")
{
type = PropType::FLEX_WRAP;
Value propValue{};
if (value == "no-wrap")
propValue.Enum = (int)Layout::FlexWrap::NO_WRAP;
if (value == "wrap")
propValue.Enum = (int)Layout::FlexWrap::WRAP;
if (value == "wrap-reversed")
propValue.Enum = (int)Layout::FlexWrap::WRAP_REVERSED;
styleGroup->SetProp(type, PropValue{ PropValueType::ENUM, propValue });
continue;
}
if (name == "justify-content")
{
type = PropType::JUSTIFY_CONTENT;
Value propValue{};
if (value == "flex-start")
propValue.Enum = (int)Layout::JustifyContent::FLEX_START;
if (value == "flex-end")
propValue.Enum = (int)Layout::JustifyContent::FLEX_END;
if (value == "center")
propValue.Enum = (int)Layout::JustifyContent::CENTER;
if (value == "space-between")
propValue.Enum = (int)Layout::JustifyContent::SPACE_BETWEEN;
if (value == "space-around")
propValue.Enum = (int)Layout::JustifyContent::SPACE_AROUND;
if (value == "space-evenly")
propValue.Enum = (int)Layout::JustifyContent::SPACE_EVENLY;
styleGroup->SetProp(type, PropValue{ PropValueType::ENUM, propValue });
continue;
}
if (name == "align-self" || name == "align-items")
{
if (name == "align-self")
type = PropType::SELF_ALIGN;
else
type = PropType::ALIGN_ITEMS;
styleGroup->SetProp(type, PropValue{ PropValueType::ENUM, propValue });
continue;
}
if (name == "flex-wrap")
{
type = PropType::FLEX_WRAP;
Value propValue{};
if (value == "no-wrap")
propValue.Enum = (int)Layout::FlexWrap::NO_WRAP;
if (value == "wrap")
propValue.Enum = (int)Layout::FlexWrap::WRAP;
if (value == "wrap-reversed")
propValue.Enum = (int)Layout::FlexWrap::WRAP_REVERSED;
Value propValue{};
if (value == "stretch")
propValue.Enum = (int)Layout::AlignItems::STRETCH;
if (value == "flex-start")
propValue.Enum = (int)Layout::AlignItems::FLEX_START;
if (value == "flex-end")
propValue.Enum = (int)Layout::AlignItems::FLEX_END;
if (value == "center")
propValue.Enum = (int)Layout::AlignItems::CENTER;
if (value == "baseline")
propValue.Enum = (int)Layout::AlignItems::BASELINE;
styleGroup->SetProp(type, PropValue{ PropValueType::ENUM, propValue });
continue;
}
if (name == "align-self" || name == "align-items")
{
if (name == "align-self")
type = PropType::SELF_ALIGN;
else
type = PropType::ALIGN_ITEMS;
styleGroup->SetProp(type, PropValue{ PropValueType::ENUM, propValue });
continue;
}
if (name == "align-content")
{
type = PropType::ALIGN_CONTENT;
Value propValue{};
if (value == "stretch")
propValue.Enum = (int)Layout::AlignItems::STRETCH;
if (value == "flex-start")
propValue.Enum = (int)Layout::AlignItems::FLEX_START;
if (value == "flex-end")
propValue.Enum = (int)Layout::AlignItems::FLEX_END;
if (value == "center")
propValue.Enum = (int)Layout::AlignItems::CENTER;
if (value == "baseline")
propValue.Enum = (int)Layout::AlignItems::BASELINE;
Value propValue{};
if (value == "stretch")
propValue.Enum = (int)Layout::AlignContent::STRETCH;
if (value == "flex-start")
propValue.Enum = (int)Layout::AlignContent::FLEX_START;
if (value == "flex-end")
propValue.Enum = (int)Layout::AlignContent::FLEX_END;
if (value == "center")
propValue.Enum = (int)Layout::AlignContent::CENTER;
if (value == "space-between")
propValue.Enum = (int)Layout::AlignContent::SPACE_BETWEEN;
if (value == "space-around")
propValue.Enum = (int)Layout::AlignContent::SPACE_AROUND;
styleGroup->SetProp(type, PropValue{ PropValueType::ENUM, propValue });
continue;
styleGroup->SetProp(type, PropValue{ PropValueType::ENUM, propValue });
continue;
}
if (name == "align-content")
{
type = PropType::ALIGN_CONTENT;
Value propValue{};
if (value == "stretch")
propValue.Enum = (int)Layout::AlignContent::STRETCH;
if (value == "flex-start")
propValue.Enum = (int)Layout::AlignContent::FLEX_START;
if (value == "flex-end")
propValue.Enum = (int)Layout::AlignContent::FLEX_END;
if (value == "center")
propValue.Enum = (int)Layout::AlignContent::CENTER;
if (value == "space-between")
propValue.Enum = (int)Layout::AlignContent::SPACE_BETWEEN;
if (value == "space-around")
propValue.Enum = (int)Layout::AlignContent::SPACE_AROUND;
styleGroup->SetProp(type, PropValue{ PropValueType::ENUM, propValue });
continue;
}
if (name == "position")
{
type = PropType::POSITION;
Value propValue{};
if (value == "relative")
propValue.Enum = (int)Layout::PositionType::RELATIVE;
if (value == "absolute")
propValue.Enum = (int)Layout::PositionType::ABSOLUTE;
styleGroup->SetProp(type, PropValue{ PropValueType::ENUM, propValue });
continue;
}
styleGroup->SetProp(type, StyleSheetParser::ParsePropType(value, type));
Logger::Log(declaration->property);
}
if (name == "position")
{
type = PropType::POSITION;
Value propValue{};
if (value == "relative")
propValue.Enum = (int)Layout::PositionType::RELATIVE;
if (value == "absolute")
propValue.Enum = (int)Layout::PositionType::ABSOLUTE;
styleGroup->SetProp(type, PropValue{ PropValueType::ENUM, propValue });
continue;
}
styleGroup->SetProp(type, StyleSheetParser::ParsePropType(value, type));
Logger::Log(declaration->property);
Logger::Log(rule->name);
}
Logger::Log(rule->name);
return true;
}
return true;
}
bool ParseSheet()
{
std::string content = FileSystem::ReadFile(this->Path);
Data = katana_parse(content.c_str(), content.length(), KatanaParserModeStylesheet);
for (int i = 0; i < Data->stylesheet->rules.length; i++)
bool ParseSheet()
{
KatanaRule* rule = (KatanaRule*)Data->stylesheet->rules.data[i];
ParseRule(rule);
std::string content = FileSystem::ReadFile(this->Path);
Data = katana_parse(content.c_str(), content.length(), KatanaParserModeStylesheet);
for (int i = 0; i < Data->stylesheet->rules.length; i++)
{
KatanaRule* rule = (KatanaRule*)Data->stylesheet->rules.data[i];
ParseRule(rule);
}
if (Data->errors.length > 0)
{
KatanaArray errors = Data->errors;
return false;
}
return true;
}
if (Data->errors.length > 0)
{
KatanaArray errors = Data->errors;
return false;
}
return true;
}
};
}
};
}
}

View File

@@ -1,157 +1,159 @@
#include "UserInterface.h"
#include <src/Vendors/pugixml/pugixml.hpp>
#include "src/Vendors/pugixml/pugixml.hpp"
#include "Styling/Stylesheet.h"
#include "yoga/YGConfig.h"
#include "InterfaceParser.h"
#include <src/UI/Font/FontLoader.h>
#include "../Core/Input.h"
#include "src/Core/Input.h"
namespace UI
{
UserInterface::UserInterface(const std::string& name)
{
m_Name = name;
font = FontLoader::LoadFont("resources/Fonts/RobotoMono-Regular.ttf");
Root = InterfaceParser::Parse("resources/Interface/Testing.interface");
if (!Root)
namespace Nuake {
namespace UI {
UserInterface::UserInterface(const std::string& name)
{
Logger::Log("Failed to generate interface structure", CRITICAL);
m_Name = name;
font = FontLoader::LoadFont("resources/Fonts/RobotoMono-Regular.ttf");
Root = InterfaceParser::Parse("resources/Interface/Testing.interface");
if (!Root)
{
Logger::Log("Failed to generate interface structure", CRITICAL);
}
yoga_config = YGConfigNew();
yoga_config->useWebDefaults = true;
CreateYogaLayout();
}
yoga_config = YGConfigNew();
yoga_config->useWebDefaults = true;
CreateYogaLayout();
}
UserInterface::~UserInterface()
{
YGConfigFree(yoga_config);
if (yoga_root)
YGNodeFreeRecursive(yoga_root);
}
void UserInterface::Reload()
{
Root = InterfaceParser::Parse("resources/Interface/Testing.interface");
if (!Root)
UserInterface::~UserInterface()
{
Logger::Log("Failed to generate interface structure", CRITICAL);
YGConfigFree(yoga_config);
if (yoga_root)
YGNodeFreeRecursive(yoga_root);
}
yoga_config = YGConfigNew();
yoga_config->useWebDefaults = true;
CreateYogaLayout();
}
Ref<UserInterface> UserInterface::New(const std::string& name)
{
return CreateRef<UserInterface>(name);
}
void UserInterface::Calculate(int available_width, int available_height)
{
YGNodeRef root = Root->YogaNode;
YGNodeCalculateLayout(root, available_width, available_height, YGDirectionLTR);
}
void UserInterface::CreateYogaLayout()
{
yoga_root = YGNodeNewWithConfig(yoga_config);
Root->YogaNode = yoga_root;
for (auto& g : Root->GetGroups())
if (Root->StyleSheet->HasStyleGroup(g))
Root->ApplyStyle(Root->StyleSheet->GetStyleGroup(g));
Root->SetYogaLayout();
CreateYogaLayoutRecursive(Root, yoga_root);
}
void UserInterface::CreateYogaLayoutRecursive(Ref<Node> node, YGNodeRef yoga_node)
{
if(node->Childrens.size() > 0)
YGNodeCalculateLayout(yoga_node, YGNodeLayoutGetWidth(yoga_node), YGNodeLayoutGetHeight(yoga_node), YGDirectionLTR);
int index = 0;
for (auto& n : node->Childrens)
void UserInterface::Reload()
{
YGNodeRef newYogaNode = YGNodeNew();
n->YogaNode = newYogaNode;
Root = InterfaceParser::Parse("resources/Interface/Testing.interface");
if (!Root)
{
Logger::Log("Failed to generate interface structure", CRITICAL);
}
for (auto& g : n->GetGroups())
yoga_config = YGConfigNew();
yoga_config->useWebDefaults = true;
CreateYogaLayout();
}
Ref<UserInterface> UserInterface::New(const std::string& name)
{
return CreateRef<UserInterface>(name);
}
void UserInterface::Calculate(int available_width, int available_height)
{
YGNodeRef root = Root->YogaNode;
YGNodeCalculateLayout(root, available_width, available_height, YGDirectionLTR);
}
void UserInterface::CreateYogaLayout()
{
yoga_root = YGNodeNewWithConfig(yoga_config);
Root->YogaNode = yoga_root;
for (auto& g : Root->GetGroups())
if (Root->StyleSheet->HasStyleGroup(g))
n->ApplyStyle(Root->StyleSheet->GetStyleGroup(g));
n->SetYogaLayout();
YGNodeInsertChild(yoga_node, newYogaNode, index);
CreateYogaLayoutRecursive(n, newYogaNode);
index++;
Root->ApplyStyle(Root->StyleSheet->GetStyleGroup(g));
Root->SetYogaLayout();
CreateYogaLayoutRecursive(Root, yoga_root);
}
}
void UserInterface::Draw(Vector2 size)
{
Calculate(size.x, size.y);
Renderer2D::BeginDraw(size);
float leftOffset = YGNodeLayoutGetLeft(Root->YogaNode);
float topOffset = YGNodeLayoutGetTop(Root->YogaNode);
Vector2 charPos = Vector2(100.f, 100.f);
Char charr = font->GetChar(89);
DrawRecursive(Root, 0);
//Renderer2D::DrawChar(charr, font, charPos, size);
}
void UserInterface::DrawRecursive(Ref<Node> node, float z)
{
if (!node)
return;
if (node->Type == NodeType::Text)
std::static_pointer_cast<TextNode>(node)->Draw(z);
else
node->Draw(z);
if (node->Childrens.size() <= 0)
return;
for (auto& c : node->Childrens)
void UserInterface::CreateYogaLayoutRecursive(Ref<Node> node, YGNodeRef yoga_node)
{
DrawRecursive(c, z + 1);
}
}
if (node->Childrens.size() > 0)
YGNodeCalculateLayout(yoga_node, YGNodeLayoutGetWidth(yoga_node), YGNodeLayoutGetHeight(yoga_node), YGDirectionLTR);
int index = 0;
for (auto& n : node->Childrens)
{
YGNodeRef newYogaNode = YGNodeNew();
n->YogaNode = newYogaNode;
void UserInterface::Update(Timestep ts)
{
// Check Input
if (Input::IsMouseButtonPressed(0))
for (auto& g : n->GetGroups())
if (Root->StyleSheet->HasStyleGroup(g))
n->ApplyStyle(Root->StyleSheet->GetStyleGroup(g));
n->SetYogaLayout();
YGNodeInsertChild(yoga_node, newYogaNode, index);
CreateYogaLayoutRecursive(n, newYogaNode);
index++;
}
}
void UserInterface::Draw(Vector2 size)
{
ConsumeMouseClick(Input::GetMousePosition());
Calculate(size.x, size.y);
Renderer2D::BeginDraw(size);
float leftOffset = YGNodeLayoutGetLeft(Root->YogaNode);
float topOffset = YGNodeLayoutGetTop(Root->YogaNode);
Vector2 charPos = Vector2(100.f, 100.f);
Char charr = font->GetChar(89);
DrawRecursive(Root, 0);
//Renderer2D::DrawChar(charr, font, charPos, size);
}
}
void UserInterface::RecursiveMouseClick(Ref<Node> node, Vector2 pos)
{
for (auto& c : node->Childrens)
void UserInterface::DrawRecursive(Ref<Node> node, float z)
{
RecursiveMouseClick(c, pos);
if (c->IsPositionInside(pos) && c->OnClickSignature != "")
this->Root->Script->CallMethod(c->OnClickSignature);
if (!node)
return;
if (node->Type == NodeType::Text)
std::static_pointer_cast<TextNode>(node)->Draw(z);
else
node->Draw(z);
if (node->Childrens.size() <= 0)
return;
for (auto& c : node->Childrens)
{
DrawRecursive(c, z + 1);
}
}
}
void UserInterface::ConsumeMouseClick(Vector2 pos)
{
void UserInterface::Update(Timestep ts)
{
// Check Input
if (Input::IsMouseButtonPressed(0))
{
ConsumeMouseClick(Input::GetMousePosition());
}
}
RecursiveMouseClick(Root, pos);
void UserInterface::RecursiveMouseClick(Ref<Node> node, Vector2 pos)
{
for (auto& c : node->Childrens)
{
RecursiveMouseClick(c, pos);
if (c->IsPositionInside(pos) && c->OnClickSignature != "")
this->Root->Script->CallMethod(c->OnClickSignature);
}
}
void UserInterface::ConsumeMouseClick(Vector2 pos)
{
RecursiveMouseClick(Root, pos);
}
}
}

View File

@@ -1,44 +1,46 @@
#pragma once
#include <src/Core/Timestep.h>
#include <src/Rendering/Framebuffer.h>
#include <src/Rendering/Buffers/Framebuffer.h>
#include <src/UI/Nodes/Rect.h>
#include "yoga/Yoga.h"
#include "Nodes/Node.h"
#include "Nodes/Canvas.h"
#include "../Core/Maths.h"
#include "src/Core/Maths.h"
#include "Styling/Stylesheet.h"
#include "Font/Font.h"
namespace UI
{
class UserInterface
{
private:
Ref<FrameBuffer> m_Framebuffer; // Texture of the interface.
std::string m_Name;
Ref<Canvas> Root;
YGConfigRef yoga_config;
YGNodeRef yoga_root;
public:
Ref<Font> font;
const int Width = 1920;
const int Height = 1080;
UserInterface(const std::string& name);
~UserInterface();
namespace Nuake {
namespace UI {
class UserInterface
{
private:
Ref<FrameBuffer> m_Framebuffer; // Texture of the interface.
std::string m_Name;
Ref<Canvas> Root;
YGConfigRef yoga_config;
YGNodeRef yoga_root;
public:
Ref<Font> font;
const int Width = 1920;
const int Height = 1080;
void Reload();
UserInterface(const std::string& name);
~UserInterface();
static Ref<UserInterface> New(const std::string& name);
void Calculate(int available_width, int available_height);
void Reload();
void CreateYogaLayout();
void CreateYogaLayoutRecursive(Ref<Node> node, YGNodeRef yoga_node);
void Draw(Vector2 size);
void DrawRecursive(Ref<Node> node, float z);
void Update(Timestep ts);
static Ref<UserInterface> New(const std::string& name);
void Calculate(int available_width, int available_height);
void RecursiveMouseClick(Ref<Node> node, Vector2 pos);
void CreateYogaLayout();
void CreateYogaLayoutRecursive(Ref<Node> node, YGNodeRef yoga_node);
void Draw(Vector2 size);
void DrawRecursive(Ref<Node> node, float z);
void Update(Timestep ts);
void ConsumeMouseClick(Vector2 pos);
};
}
void RecursiveMouseClick(Ref<Node> node, Vector2 pos);
void ConsumeMouseClick(Vector2 pos);
};
}
}