Major cleanup.
Moved to namespace Cleanup includes
This commit is contained in:
@@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include "Canvas.h"
|
||||
Canvas::Canvas()
|
||||
{
|
||||
|
||||
namespace Nuake {
|
||||
Canvas::Canvas()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user