ui loader and some refactoring

This commit is contained in:
Eduardo Bart 2011-04-10 17:40:44 -03:00
parent 1f78f93096
commit 992e0a8a6b
36 changed files with 646 additions and 425 deletions

View File

@ -68,6 +68,7 @@ SET(SOURCES
src/framework/core/engine.cpp src/framework/core/engine.cpp
# framework utilities # framework utilities
src/framework/util/color.cpp
src/framework/util/util.cpp src/framework/util/util.cpp
src/framework/util/logger.cpp src/framework/util/logger.cpp
src/framework/util/rsa.cpp src/framework/util/rsa.cpp
@ -84,12 +85,13 @@ SET(SOURCES
src/framework/graphics/graphics.cpp src/framework/graphics/graphics.cpp
# framework ui # framework ui
src/framework/ui/anchorlayout.cpp src/framework/ui/uilayout.cpp
src/framework/ui/uielement.cpp src/framework/ui/uielement.cpp
src/framework/ui/uielementskin.cpp src/framework/ui/uielementskin.cpp
src/framework/ui/uibuttonskin.cpp src/framework/ui/uibuttonskin.cpp
src/framework/ui/uicontainer.cpp src/framework/ui/uicontainer.cpp
src/framework/ui/uiskins.cpp src/framework/ui/uiskins.cpp
src/framework/ui/uiloader.cpp
src/framework/ui/uipanel.cpp src/framework/ui/uipanel.cpp
src/framework/ui/uibutton.cpp src/framework/ui/uibutton.cpp
src/framework/ui/uilabel.cpp src/framework/ui/uilabel.cpp

View File

@ -35,7 +35,7 @@ bool Configs::load(const std::string& fileName)
return false; return false;
std::string fileContents = g_resources.loadTextFile(fileName); std::string fileContents = g_resources.loadTextFile(fileName);
if(fileContents.size() == 0) if(fileContents.size())
return false; return false;
std::istringstream fin(fileContents); std::istringstream fin(fileContents);
@ -52,8 +52,8 @@ bool Configs::load(const std::string& fileName)
it.second() >> value; it.second() >> value;
m_confsMap[key] = value; m_confsMap[key] = value;
} }
} catch (YAML::ParserException& e) { } catch (YAML::Exception& e) {
logError("Malformed configuration file!"); logError("Malformed config file: %s", e.what());
return false; return false;
} }

View File

@ -37,7 +37,7 @@ void Engine::init()
{ {
// initialize stuff // initialize stuff
g_graphics.init(); g_graphics.init();
g_fonts.init(); g_fonts.init("tibia-12px-rounded");
} }
void Engine::terminate() void Engine::terminate()
@ -52,6 +52,7 @@ void Engine::terminate()
void Engine::run() void Engine::run()
{ {
Font *defaultFont = g_fonts.getDefaultFont();
int ticks = Platform::getTicks(); int ticks = Platform::getTicks();
int lastFpsTicks = ticks; int lastFpsTicks = ticks;
int frameCount = 0; int frameCount = 0;
@ -87,8 +88,8 @@ void Engine::run()
// render fps // render fps
if(m_calculateFps) { if(m_calculateFps) {
std::string fpsText = format("FPS: %d", fps); std::string fpsText = format("FPS: %d", fps);
Size textSize = g_defaultFont->calculateTextRectSize(fpsText); Size textSize = defaultFont->calculateTextRectSize(fpsText);
g_defaultFont->renderText(fpsText, Point(g_graphics.getScreenSize().width() - textSize.width() - 10, 10)); defaultFont->renderText(fpsText, Point(g_graphics.getScreenSize().width() - textSize.width() - 10, 10));
} }
// swap buffers // swap buffers
@ -119,7 +120,7 @@ void Engine::render()
g_graphics.beginRender(); g_graphics.beginRender();
if(m_currentState) if(m_currentState)
m_currentState->render(); m_currentState->render();
g_ui->render(); UIContainer::getRootContainer()->render();
g_graphics.endRender(); g_graphics.endRender();
} }
@ -132,7 +133,7 @@ void Engine::onClose()
void Engine::onResize(const Size& size) void Engine::onResize(const Size& size)
{ {
g_graphics.resize(size); g_graphics.resize(size);
g_ui->setSize(size); UIContainer::getRootContainer()->setSize(size);
if(m_currentState) if(m_currentState)
m_currentState->onResize(size); m_currentState->onResize(size);
@ -141,7 +142,7 @@ void Engine::onResize(const Size& size)
void Engine::onInputEvent(const InputEvent& event) void Engine::onInputEvent(const InputEvent& event)
{ {
// inputs goest to gui first // inputs goest to gui first
if(!g_ui->onInputEvent(event)) { if(!UIContainer::getRootContainer()->onInputEvent(event)) {
// if gui didnt capture the input then goes to the state // if gui didnt capture the input then goes to the state
if(m_currentState) if(m_currentState)
m_currentState->onInputEvent(event); m_currentState->onInputEvent(event);

View File

@ -43,7 +43,7 @@ bool Resources::setWriteDir(const std::string& path)
bool ret = (bool)PHYSFS_setWriteDir(path.c_str()); bool ret = (bool)PHYSFS_setWriteDir(path.c_str());
if(!ret) if(!ret)
logError("Could not set the path \"%s\" as write directory, file write will not work.", path.c_str()); logError("Could not set the path \"%s\" as write directory, file write will not work correctly.", path.c_str());
return ret; return ret;
} }

View File

@ -84,70 +84,64 @@ void BorderedImage::draw(const Rect& screenCoords)
if(screenCoords.size() <= m_cornersSize) if(screenCoords.size() <= m_cornersSize)
return; return;
const Size& textureSize = m_texture->getSize();
Rect rectCoords; Rect rectCoords;
Size centerSize = screenCoords.size() - m_cornersSize; Size centerSize = screenCoords.size() - m_cornersSize;
g_graphics._beginTextureRender(m_texture.get());
// first the center // first the center
rectCoords = Rect(screenCoords.left() + m_leftBorderTexCoords.width(), rectCoords = Rect(screenCoords.left() + m_leftBorderTexCoords.width(),
screenCoords.top() + m_topBorderTexCoords.height(), screenCoords.top() + m_topBorderTexCoords.height(),
centerSize); centerSize);
g_graphics._drawRepeatedTexturedRect(rectCoords, m_centerTexCoords, textureSize); g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_centerTexCoords);
// top left corner // top left corner
rectCoords = Rect(screenCoords.topLeft(), rectCoords = Rect(screenCoords.topLeft(),
m_topLeftCornerTexCoords.size()); m_topLeftCornerTexCoords.size());
g_graphics._drawTexturedRect(rectCoords, m_topLeftCornerTexCoords, textureSize); g_graphics.drawTexturedRect(rectCoords, m_texture, m_topLeftCornerTexCoords);
// top // top
rectCoords = Rect(screenCoords.left() + m_topLeftCornerTexCoords.width(), rectCoords = Rect(screenCoords.left() + m_topLeftCornerTexCoords.width(),
screenCoords.topLeft().y, screenCoords.topLeft().y,
centerSize.width(), centerSize.width(),
m_topBorderTexCoords.height()); m_topBorderTexCoords.height());
g_graphics._drawRepeatedTexturedRect(rectCoords, m_topBorderTexCoords, textureSize); g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_topBorderTexCoords);
// top right corner // top right corner
rectCoords = Rect(screenCoords.left() + m_topLeftCornerTexCoords.width() + centerSize.width(), rectCoords = Rect(screenCoords.left() + m_topLeftCornerTexCoords.width() + centerSize.width(),
screenCoords.top(), screenCoords.top(),
m_topRightCornerTexCoords.size()); m_topRightCornerTexCoords.size());
g_graphics._drawTexturedRect(rectCoords, m_topRightCornerTexCoords, textureSize); g_graphics.drawTexturedRect(rectCoords, m_texture, m_topRightCornerTexCoords);
// left // left
rectCoords = Rect(screenCoords.left(), rectCoords = Rect(screenCoords.left(),
screenCoords.top() + m_topLeftCornerTexCoords.height(), screenCoords.top() + m_topLeftCornerTexCoords.height(),
m_leftBorderTexCoords.width(), m_leftBorderTexCoords.width(),
centerSize.height()); centerSize.height());
g_graphics._drawRepeatedTexturedRect(rectCoords, m_leftBorderTexCoords, textureSize); g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_leftBorderTexCoords);
// right // right
rectCoords = Rect(screenCoords.left() + m_leftBorderTexCoords.width() + centerSize.width(), rectCoords = Rect(screenCoords.left() + m_leftBorderTexCoords.width() + centerSize.width(),
screenCoords.top() + m_topRightCornerTexCoords.height(), screenCoords.top() + m_topRightCornerTexCoords.height(),
m_rightBorderTexCoords.width(), m_rightBorderTexCoords.width(),
centerSize.height()); centerSize.height());
g_graphics._drawRepeatedTexturedRect(rectCoords, m_rightBorderTexCoords, textureSize); g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_rightBorderTexCoords);
// bottom left corner // bottom left corner
rectCoords = Rect(screenCoords.left(), rectCoords = Rect(screenCoords.left(),
screenCoords.top() + m_topBorderTexCoords.height() + centerSize.height(), screenCoords.top() + m_topBorderTexCoords.height() + centerSize.height(),
m_bottomLeftCornerTexCoords.size()); m_bottomLeftCornerTexCoords.size());
g_graphics._drawTexturedRect(rectCoords, m_bottomLeftCornerTexCoords, textureSize); g_graphics.drawTexturedRect(rectCoords, m_texture, m_bottomLeftCornerTexCoords);
// bottom // bottom
rectCoords = Rect(screenCoords.left() + m_bottomLeftCornerTexCoords.width(), rectCoords = Rect(screenCoords.left() + m_bottomLeftCornerTexCoords.width(),
screenCoords.top() + m_topBorderTexCoords.height() + centerSize.height(), screenCoords.top() + m_topBorderTexCoords.height() + centerSize.height(),
centerSize.width(), centerSize.width(),
m_bottomBorderTexCoords.height()); m_bottomBorderTexCoords.height());
g_graphics._drawRepeatedTexturedRect(rectCoords, m_bottomBorderTexCoords, textureSize); g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_bottomBorderTexCoords);
// bottom right corner // bottom right corner
rectCoords = Rect(screenCoords.left() + m_bottomLeftCornerTexCoords.width() + centerSize.width(), rectCoords = Rect(screenCoords.left() + m_bottomLeftCornerTexCoords.width() + centerSize.width(),
screenCoords.top() + m_topRightCornerTexCoords.height() + centerSize.height(), screenCoords.top() + m_topRightCornerTexCoords.height() + centerSize.height(),
m_bottomRightCornerTexCoords.size()); m_bottomRightCornerTexCoords.size());
g_graphics._drawTexturedRect(rectCoords, m_bottomRightCornerTexCoords, textureSize); g_graphics.drawTexturedRect(rectCoords, m_texture, m_bottomRightCornerTexCoords);
//g_graphics._drawBoundingRect(screenCoords, Color(0xFF00FF00), 1);
g_graphics._endTextureRender();
} }

View File

@ -27,11 +27,7 @@
#include "textures.h" #include "textures.h"
#include "graphics.h" #include "graphics.h"
Font::Font() :
m_glyphHeight(10),
m_topMargin(0)
{
}
void Font::calculateGlyphsWidthsAutomatically(const Size& glyphSize) void Font::calculateGlyphsWidthsAutomatically(const Size& glyphSize)
{ {
@ -73,12 +69,11 @@ bool Font::load(const std::string& file)
{ {
std::string fileContents = g_resources.loadTextFile(file); std::string fileContents = g_resources.loadTextFile(file);
if(!fileContents.size()) { if(!fileContents.size()) {
logError("Empty font file \"%s", file.c_str()); logError("Coult not load font file \"%s", file.c_str());
return false; return false;
} }
std::istringstream fin(fileContents); std::istringstream fin(fileContents);
std::string textureName; std::string textureName;
Size glyphSize; Size glyphSize;
@ -88,22 +83,25 @@ bool Font::load(const std::string& file)
YAML::Node doc; YAML::Node doc;
parser.GetNextDocument(doc); parser.GetNextDocument(doc);
// required values
doc["glyph height"] >> m_glyphHeight; doc["glyph height"] >> m_glyphHeight;
doc["glyph spacing"] >> m_glyphSpacing;
doc["top margin"] >> m_topMargin;
doc["image glyph size"] >> glyphSize; doc["image glyph size"] >> glyphSize;
doc["image"] >> textureName; doc["image"] >> textureName;
// optional values
if(doc.FindValue("glyph spacing"))
doc["glyph spacing"] >> m_glyphSpacing;
if(doc.FindValue("top margin"))
doc["top margin"] >> m_topMargin;
// load texture
m_texture = g_textures.get("fonts/" + textureName); m_texture = g_textures.get("fonts/" + textureName);
if(!m_texture) { if(!m_texture) {
logError("Failed to load image for font \"%s\"", file.c_str()); logError("Failed to load image for font file \"%s\"", file.c_str());
return false; return false;
} }
// set glyphs height // auto calculate widths
for(int glyph = 32; glyph < 256; ++glyph) {
}
calculateGlyphsWidthsAutomatically(glyphSize); calculateGlyphsWidthsAutomatically(glyphSize);
// read custom widths // read custom widths
@ -121,13 +119,12 @@ bool Font::load(const std::string& file)
int numHorizontalGlyphs = m_texture->getSize().width() / glyphSize.width(); int numHorizontalGlyphs = m_texture->getSize().width() / glyphSize.width();
for(int glyph = 32; glyph< 256; ++glyph) { for(int glyph = 32; glyph< 256; ++glyph) {
m_glyphsTextureCoords[glyph].setRect(((glyph - 32) % numHorizontalGlyphs) * glyphSize.width(), m_glyphsTextureCoords[glyph].setRect(((glyph - 32) % numHorizontalGlyphs) * glyphSize.width(),
((glyph - 32) / numHorizontalGlyphs) * glyphSize.height(), ((glyph - 32) / numHorizontalGlyphs) * glyphSize.height(),
m_glyphsSize[glyph].width(), m_glyphsSize[glyph].width(),
m_glyphHeight); m_glyphHeight);
} }
} catch (YAML::Exception& e) {
} catch (YAML::ParserException& e) { logError("Malformed font file \"%s\":\n %s", file.c_str(), e.what());
logError("Malformed font file \"%s\"", file.c_str());
return false; return false;
} }
@ -146,18 +143,12 @@ void Font::renderText(const std::string& text,
const Rect& screenCoords, const Rect& screenCoords,
int align, int align,
const Color& color, const Color& color,
const Point& startInternalPos, const Point& startInternalPos)
bool debug)
{ {
// prevent glitches from invalid rects // prevent glitches from invalid rects
if(!screenCoords.isValid()) if(!screenCoords.isValid())
return; return;
// begin texture rendering
g_graphics.setColor(color);
g_graphics._beginTextureRender(m_texture.get());
const Size& textureSize = m_texture->getSize();
int textLenght = text.length(); int textLenght = text.length();
// map glyphs positions // map glyphs positions
@ -227,17 +218,8 @@ void Font::renderText(const std::string& text,
} }
// render glyph // render glyph
g_graphics._drawTexturedRect(glyphScreenCoords, glyphTextureCoords, textureSize); g_graphics.drawTexturedRect(glyphScreenCoords, m_texture, glyphTextureCoords, color);
//g_graphics._drawBoundingRect(glyphScreenCoords, Color(0xFF0000FF));
} }
// end texture redering
g_graphics._endTextureRender();
g_graphics.resetColor();
if(debug)
g_graphics.drawBoundingRect(screenCoords.expanded(1), Color(0xFF00FF00));
} }
Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size *textBoxSize) Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size *textBoxSize)

View File

@ -45,8 +45,10 @@ enum EAlign {
class Font class Font
{ {
public: public:
Font(); Font(const std::string& name) :
virtual ~Font() { } m_name(name),
m_glyphHeight(10),
m_topMargin(0) { }
/// Load font from file /// Load font from file
bool load(const std::string &file); bool load(const std::string &file);
@ -62,9 +64,8 @@ public:
void renderText(const std::string& text, void renderText(const std::string& text,
const Rect& screenCoords, const Rect& screenCoords,
int align = ALIGN_TOP_LEFT, int align = ALIGN_TOP_LEFT,
const Color& color = Color(0xFFFFFFFF), const Color& color = Color::white,
const Point& startInternalPos = Point(), const Point& startInternalPos = Point());
bool debug = false);
/// Calculate glyphs positions to use on render, also calculates textBoxSize if wanted /// Calculate glyphs positions to use on render, also calculates textBoxSize if wanted
Point *calculateGlyphsPositions(const std::string& text, int align = ALIGN_TOP_LEFT, Size *textBoxSize = NULL); Point *calculateGlyphsPositions(const std::string& text, int align = ALIGN_TOP_LEFT, Size *textBoxSize = NULL);
@ -72,9 +73,12 @@ public:
/// Simulate render and calculate text size /// Simulate render and calculate text size
Size calculateTextRectSize(const std::string& text); Size calculateTextRectSize(const std::string& text);
const std::string& getName() const { return m_name; }
private: private:
void calculateGlyphsWidthsAutomatically(const Size& glyphSize); void calculateGlyphsWidthsAutomatically(const Size& glyphSize);
std::string m_name;
int m_glyphHeight; int m_glyphHeight;
int m_topMargin; int m_topMargin;
Size m_glyphSpacing; Size m_glyphSpacing;
@ -83,4 +87,6 @@ private:
Size m_glyphsSize[256]; Size m_glyphsSize[256];
}; };
typedef std::shared_ptr<Font> FontPtr;
#endif // FONT_H #endif // FONT_H

View File

@ -23,13 +23,11 @@
#include "fonts.h" #include "fonts.h"
#include "font.h"
#include "core/resources.h" #include "core/resources.h"
Fonts g_fonts; Fonts g_fonts;
Font *g_defaultFont = NULL;
void Fonts::init() void Fonts::init(const std::string& defaultFontName)
{ {
// load all fonts // load all fonts
std::list<std::string> files = g_resources.getDirectoryFiles("fonts"); std::list<std::string> files = g_resources.getDirectoryFiles("fonts");
@ -37,27 +35,28 @@ void Fonts::init()
if(boost::ends_with(file, ".yml")) { if(boost::ends_with(file, ".yml")) {
std::string name = file; std::string name = file;
boost::erase_first(name, ".yml"); boost::erase_first(name, ".yml");
std::shared_ptr<Font> font(new Font); FontPtr font(new Font(name));
font->load("fonts/" + file); if(font->load("fonts/" + file)) {
m_fonts[name] = font; m_fonts.push_back(font);
if(name == defaultFontName)
m_defaultFont = font;
}
} }
} }
// set default font if(!m_defaultFont)
g_defaultFont = get("tibia-12px-rounded"); logFatal("Could not load the default font \"%s\"\n", defaultFontName.c_str());
if(!g_defaultFont)
logFatal("Default font not found!");
} }
Font* Fonts::get(const std::string& fontName) Font* Fonts::get(const std::string& fontName)
{ {
// find font by name // find font by name
auto it = m_fonts.find(fontName); for(auto it = m_fonts.begin(); it != m_fonts.end(); ++it) {
if(it != m_fonts.end()) { if((*it)->getName() == fontName)
return it->second.get(); return (*it).get();
} }
logError("Font \"%s\" not found", fontName.c_str()); logError("Font \"%s\" not found, returing the default one", fontName.c_str());
return NULL; return m_defaultFont.get();
} }

View File

@ -34,19 +34,22 @@ public:
Fonts() { } Fonts() { }
/// Initialize all fonts /// Initialize all fonts
void init(); void init(const std::string& defaultFontName);
/// Get a font by name
Font *get(const std::string& fontName);
/// Terminate all fonts /// Terminate all fonts
void terminate() { } void terminate() { }
/// Get a font by name
Font *get(const std::string& fontName);
/// Get the default font
Font *getDefaultFont() { return m_defaultFont.get(); };
private: private:
std::map<std::string, std::shared_ptr<Font> > m_fonts; std::vector<FontPtr> m_fonts;
FontPtr m_defaultFont;
}; };
extern Fonts g_fonts; extern Fonts g_fonts;
extern Font *g_defaultFont;
#endif // FONTS_H #endif // FONTS_H

View File

@ -123,49 +123,19 @@ void Graphics::endRender()
} }
void Graphics::drawTexturedRect(const Rect& screenCoords, const TexturePtr& texture, const Rect& textureCoords, const Color& color)
void Graphics::setColor(const Color& color)
{ {
if(screenCoords.size().isEmpty())
return;
glColor4ubv(color.rgbaPtr()); glColor4ubv(color.rgbaPtr());
}
void Graphics::resetColor()
{
glColor4ub(0xFF, 0xFF, 0xFF, 0xFF);
}
void Graphics::_beginTextureRender(const Texture *texture)
{
glBindTexture(GL_TEXTURE_2D, texture->getTextureId());
glBegin(GL_QUADS);
}
void Graphics::_endTextureRender()
{
glEnd();
}
void Graphics::drawTexturedRect(const Rect& screenCoords, const Texture *texture, const Rect& textureCoords)
{
if(screenCoords.size().isEmpty())
return;
glBindTexture(GL_TEXTURE_2D, texture->getTextureId());
glBegin(GL_QUADS);
_drawTexturedRect(screenCoords, textureCoords, texture->getSize());
glEnd();
}
void Graphics::_drawTexturedRect(const Rect& screenCoords, const Rect& textureCoords, const Size& textureSize)
{
if(screenCoords.size().isEmpty())
return;
// rect correction for opengl // rect correction for opengl
int right = screenCoords.right() + 1; int right = screenCoords.right() + 1;
int bottom = screenCoords.bottom() + 1; int bottom = screenCoords.bottom() + 1;
int top = screenCoords.top(); int top = screenCoords.top();
int left = screenCoords.left(); int left = screenCoords.left();
const Size& textureSize = texture->getSize();
float textureRight = 0.0f; float textureRight = 0.0f;
float textureBottom = 1.0f; float textureBottom = 1.0f;
@ -179,24 +149,18 @@ void Graphics::_drawTexturedRect(const Rect& screenCoords, const Rect& textureCo
textureLeft = (float)textureCoords.left() / textureSize.width(); textureLeft = (float)textureCoords.left() / textureSize.width();
} }
glBindTexture(GL_TEXTURE_2D, texture->getTextureId());
glBegin(GL_QUADS);
glTexCoord2f(textureLeft, textureTop); glVertex2i(left, top); glTexCoord2f(textureLeft, textureTop); glVertex2i(left, top);
glTexCoord2f(textureLeft, textureBottom); glVertex2i(left, bottom); glTexCoord2f(textureLeft, textureBottom); glVertex2i(left, bottom);
glTexCoord2f(textureRight, textureBottom); glVertex2i(right, bottom); glTexCoord2f(textureRight, textureBottom); glVertex2i(right, bottom);
glTexCoord2f(textureRight, textureTop); glVertex2i(right, top); glTexCoord2f(textureRight, textureTop); glVertex2i(right, top);
}
void Graphics::drawRepeatedTexturedRect(const Rect& screenCoords, const Texture* texture, const Rect& texCoords)
{
if(screenCoords.size().isEmpty())
return;
glBindTexture(GL_TEXTURE_2D, texture->getTextureId());
glBegin(GL_QUADS);
_drawRepeatedTexturedRect(screenCoords, texCoords, texture->getSize());
glEnd(); glEnd();
} }
void Graphics::_drawRepeatedTexturedRect(const Rect& screenCoords, const Rect& textureCoords, const Size& textureSize) void Graphics::drawRepeatedTexturedRect(const Rect& screenCoords, const TexturePtr& texture, const Rect& textureCoords, const Color& color)
{ {
if(screenCoords.size().isEmpty()) if(screenCoords.size().isEmpty())
return; return;
@ -219,20 +183,19 @@ void Graphics::_drawRepeatedTexturedRect(const Rect& screenCoords, const Rect& t
} }
partialCoords.translate(screenCoords.topLeft()); partialCoords.translate(screenCoords.topLeft());
_drawTexturedRect(partialCoords, partialTextureCoords, textureSize); drawTexturedRect(partialCoords, texture, partialTextureCoords, color);
} }
} }
} }
void Graphics::drawFilledRect(const Rect& screenCoords, const Color& color)
void Graphics::drawColoredRect(const Rect& screenCoords, const Color& color)
{ {
if(screenCoords.size().isEmpty()) if(screenCoords.size().isEmpty())
return; return;
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
setColor(color); glColor4ubv(color.rgbaPtr());
// rect correction for opengl // rect correction for opengl
int right = screenCoords.right() + 1; int right = screenCoords.right() + 1;
@ -248,8 +211,6 @@ void Graphics::drawColoredRect(const Rect& screenCoords, const Color& color)
glEnd(); glEnd();
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
resetColor();
} }
@ -260,7 +221,7 @@ void Graphics::drawBoundingRect(const Rect& screenCoords, const Color& color, in
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
setColor(color); glColor4ubv(color.rgbaPtr());
// rect correction for opengl // rect correction for opengl
int right = screenCoords.right()+1; int right = screenCoords.right()+1;
@ -295,13 +256,4 @@ void Graphics::drawBoundingRect(const Rect& screenCoords, const Color& color, in
glEnd(); glEnd();
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
resetColor();
}
void Graphics::_drawBoundingRect(const Rect& screenCoords, const Color& color, int innerLineWidth)
{
glEnd();
drawBoundingRect(screenCoords, color, innerLineWidth);
glBegin(GL_QUADS);
} }

View File

@ -26,15 +26,17 @@
#define GRAPHICS_H #define GRAPHICS_H
#include "prerequisites.h" #include "prerequisites.h"
#include "texture.h"
class Texture;
class Graphics class Graphics
{ {
public: public:
Graphics() { } Graphics() { }
/// Initialize graphics
void init(); void init();
/// Termiante graphics
void terminate(); void terminate();
/// Check if a GL extension is supported /// Check if a GL extension is supported
@ -54,21 +56,10 @@ public:
const Size& getScreenSize() const { return m_screenSize; } const Size& getScreenSize() const { return m_screenSize; }
void setColor(const Color& color); void drawTexturedRect(const Rect& screenCoords, const TexturePtr& texture, const Rect& textureCoords = Rect(), const Color& color = Color::white);
void resetColor(); void drawRepeatedTexturedRect(const Rect& screenCoords, const TexturePtr& texture, const Rect& textureCoords, const Color& color = Color::white);
void drawFilledRect(const Rect& screenCoords, const Color& color);
// high level rendering void drawBoundingRect(const Rect& screenCoords, const Color& color = Color::green, int innerLineWidth = 1);
void drawTexturedRect(const Rect& screenCoords, const Texture *texture, const Rect& texCoords = Rect());
void drawRepeatedTexturedRect(const Rect& screenCoords, const Texture *texture, const Rect& texCoords);
void drawColoredRect(const Rect& screenCoords, const Color& color);
void drawBoundingRect(const Rect& screenCoords, const Color& color, int innerLineWidth = 1);
// lower level rendering
void _beginTextureRender(const Texture *texture);
void _drawTexturedRect(const Rect& screenCoords, const Rect& textureCoords, const Size& textureSize);
void _drawRepeatedTexturedRect(const Rect& screenCoords, const Rect& textureCoords, const Size& textureSize);
void _drawBoundingRect(const Rect& screenCoords, const Color& color, int innerLineWidth = 1);
void _endTextureRender();
private: private:
Size m_screenSize; Size m_screenSize;

View File

@ -37,14 +37,9 @@ Image::Image(const std::string& texture, Rect textureCoords) :
m_texture = g_textures.get(texture); m_texture = g_textures.get(texture);
} }
void Image::enableBilinearFilter()
{
m_texture->enableBilinearFilter();
}
void Image::draw(const Rect& screenCoords) void Image::draw(const Rect& screenCoords)
{ {
g_graphics.drawTexturedRect(screenCoords, m_texture.get(), m_textureCoords); g_graphics.drawTexturedRect(screenCoords, m_texture, m_textureCoords);
} }

View File

@ -36,7 +36,7 @@ public:
Image(const std::string& texture); Image(const std::string& texture);
Image(const std::string& texture, Rect textureCoords); Image(const std::string& texture, Rect textureCoords);
void enableBilinearFilter(); /// Draw image on screen
virtual void draw(const Rect& screenCoords); virtual void draw(const Rect& screenCoords);
protected: protected:

View File

@ -29,9 +29,9 @@
Texture::Texture(int width, int height, int components, uchar *pixels) Texture::Texture(int width, int height, int components, uchar *pixels)
{ {
m_size.setWidth(width); m_size.setSize(width, height);
m_size.setHeight(height);
// generate opengl texture
glGenTextures(1, &m_textureId); glGenTextures(1, &m_textureId);
glBindTexture(GL_TEXTURE_2D, m_textureId); glBindTexture(GL_TEXTURE_2D, m_textureId);
@ -51,11 +51,14 @@ Texture::Texture(int width, int height, int components, uchar *pixels)
break; break;
} }
// load the pixels into opengl memory
glTexImage2D(GL_TEXTURE_2D, 0, components, width, height, 0, format, GL_UNSIGNED_BYTE, pixels); glTexImage2D(GL_TEXTURE_2D, 0, components, width, height, 0, format, GL_UNSIGNED_BYTE, pixels);
// disable texture border
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// nearest filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
} }
@ -75,6 +78,7 @@ void Texture::enableBilinearFilter()
uchar *Texture::getPixels() uchar *Texture::getPixels()
{ {
// copy pixels from opengl memory
uchar *pixels = new uchar[m_size.area()*4]; uchar *pixels = new uchar[m_size.area()*4];
glBindTexture(GL_TEXTURE_2D, m_textureId); glBindTexture(GL_TEXTURE_2D, m_textureId);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

View File

@ -41,23 +41,22 @@ TexturePtr Textures::get(const std::string& textureFile)
texture = it->second.lock(); texture = it->second.lock();
} }
if(!texture) { // load texture // texture not found, load it
if(!texture) {
// currently only png textures are supported // currently only png textures are supported
if(!boost::ends_with(textureFile, ".png")) { if(!boost::ends_with(textureFile, ".png"))
logFatal("Unable to load texture %s, file format no supported.", textureFile.c_str()); logFatal("Unable to load texture %s, file format no supported.", textureFile.c_str());
return texture;
}
// load texture file data
uint fileSize; uint fileSize;
uchar *textureFileData = g_resources.loadFile(textureFile, &fileSize); uchar *textureFileData = g_resources.loadFile(textureFile, &fileSize);
if(!textureFileData) { if(!textureFileData)
logFatal("Unable to load texture %s, file could not be read.", textureFile.c_str()); logFatal("Unable to load texture %s, file could not be read.", textureFile.c_str());
return texture;
}
// load the texture
texture = TexturePtr(TextureLoader::loadPNG(textureFileData)); texture = TexturePtr(TextureLoader::loadPNG(textureFileData));
if(!texture) if(!texture)
logFatal("Unable to load texture %s, loading error.", textureFile.c_str()); logFatal("Unable to load texture %s", textureFile.c_str());
delete[] textureFileData; delete[] textureFileData;
} }

View File

@ -36,5 +36,6 @@
#include "uiskins.h" #include "uiskins.h"
#include "uiwindow.h" #include "uiwindow.h"
#include "uitextedit.h" #include "uitextedit.h"
#include "uiloader.h"
#endif // UI_H #endif // UI_H

View File

@ -26,12 +26,6 @@
#include "graphics/fonts.h" #include "graphics/fonts.h"
#include "graphics/font.h" #include "graphics/font.h"
void UIButton::load(const YAML::Node& node)
{
UIElement::load(node);
node["text"] >> m_text;
}
void UIButton::render() void UIButton::render()
{ {
UIElement::render(); UIElement::render();

View File

@ -40,11 +40,12 @@ public:
UIElement(); UIElement();
} }
void load(const YAML::Node& node);
virtual void render(); virtual void render();
bool onInputEvent(const InputEvent& event); bool onInputEvent(const InputEvent& event);
void setText(const std::string& text) { m_text = text; }
const std::string& getText() const { return m_text; }
UI::EButtonState getState() { return m_state; } UI::EButtonState getState() { return m_state; }
void onClick(const Callback& callback) { m_buttonClickCallback = callback; } void onClick(const Callback& callback) { m_buttonClickCallback = callback; }

View File

@ -30,90 +30,11 @@
#include "uitextedit.h" #include "uitextedit.h"
#include "uiwindow.h" #include "uiwindow.h"
UIContainerPtr g_ui(new UIContainer); UIContainerPtr rootContainer(new UIContainer);
UIElementPtr createElementFromDescription(std::string elementId) UIContainerPtr& UIContainer::getRootContainer()
{ {
UIElementPtr element; return rootContainer;
std::vector<std::string> split;
boost::split(split, elementId, boost::is_any_of("-"));
if(split.size() != 2) {
logError("incorrect element id format: %s", elementId.c_str());
return element;
}
std::string elementType = split[1];
if(elementType == "panel") {
element = UIElementPtr(new UIPanel);
} else if(elementType == "button") {
element = UIElementPtr(new UIButton);
} else if(elementType == "label") {
element = UIElementPtr(new UILabel);
} else if(elementType == "window") {
element = UIElementPtr(new UIWindow);
} else if(elementType == "textEdit") {
element = UIElementPtr(new UITextEdit);
}
if(element)
element->setId(elementId);
return element;
}
void UIContainer::load(const YAML::Node& node)
{
UIElement::load(node);
for(auto it = node.begin(); it != node.end(); ++it) {
std::string elementDesc;
it.first() >> elementDesc;
if(elementDesc.find("-") != std::string::npos) {
UIElementPtr element = createElementFromDescription(elementDesc);
if(element) {
addChild(element);
element->load(it.second());
}
}
}
}
UIContainerPtr UIContainer::load(const std::string& file)
{
//TODO: handle errors
//TODO: display errors in which file and line
UIContainerPtr container;
std::string fileContents = g_resources.loadTextFile(file);
if(!fileContents.size()) {
logFatal("could not load ui file \"%s", file.c_str());
return UIContainerPtr();
}
std::istringstream fin(fileContents);
try {
YAML::Parser parser(fin);
YAML::Node doc;
parser.GetNextDocument(doc);
std::string elementDesc;
doc.begin().first() >> elementDesc;
UIElementPtr element = createElementFromDescription(elementDesc);
if(element) {
g_ui->addChild(element);
element->load(doc.begin().second());
return element->asUIContainer();
}
} catch (YAML::ParserException& e) {
logError("Malformed ui file \"%s\": %s", file.c_str(), e.what());
return UIContainerPtr();
}
return container;
} }
void UIContainer::addChild(UIElementPtr child) void UIContainer::addChild(UIElementPtr child)

View File

@ -34,11 +34,6 @@ public:
UIContainer(UI::EElementType type = UI::Container) : UIElement(type) { } UIContainer(UI::EElementType type = UI::Container) : UIElement(type) { }
virtual ~UIContainer() { } virtual ~UIContainer() { }
virtual void load(const YAML::Node& node);
//TODO: move this shit
static UIContainerPtr load(const std::string& file);
void addChild(UIElementPtr child); void addChild(UIElementPtr child);
void removeChild(UIElementPtr child); void removeChild(UIElementPtr child);
UIElementPtr getChildById(const std::string& id); UIElementPtr getChildById(const std::string& id);
@ -56,11 +51,11 @@ public:
UIContainerPtr asUIContainer() { return std::static_pointer_cast<UIContainer>(shared_from_this()); } UIContainerPtr asUIContainer() { return std::static_pointer_cast<UIContainer>(shared_from_this()); }
static UIContainerPtr& getRootContainer();
protected: protected:
std::list<UIElementPtr> m_children; std::list<UIElementPtr> m_children;
UIElementPtr m_activeElement; UIElementPtr m_activeElement;
}; };
extern UIContainerPtr g_ui;
#endif // UICONTAINER_H #endif // UICONTAINER_H

View File

@ -27,7 +27,7 @@
#include "uielementskin.h" #include "uielementskin.h"
UIElement::UIElement(UI::EElementType type) : UIElement::UIElement(UI::EElementType type) :
AnchorLayout(), UILayout(),
m_type(type), m_type(type),
m_skin(NULL), m_skin(NULL),
m_visible(true), m_visible(true),
@ -38,107 +38,6 @@ UIElement::UIElement(UI::EElementType type) :
setSkin(g_uiSkins.getElementSkin(type)); setSkin(g_uiSkins.getElementSkin(type));
} }
void UIElement::load(const YAML::Node& node)
{
if(node.FindValue("skin"))
setSkin(g_uiSkins.getElementSkin(m_type, node["skin"]));
if(node.FindValue("size")) {
Size size;
node["size"] >> size;
setSize(size);
}
int margin;
if(node.FindValue("margin.left")) {
node["margin.left"] >> margin;
setMarginLeft(margin);
}
if(node.FindValue("margin.right")) {
node["margin.right"] >> margin;
setMarginRight(margin);
}
if(node.FindValue("margin.top")) {
node["margin.top"] >> margin;
setMarginTop(margin);
}
if(node.FindValue("margin.bottom")) {
node["margin.bottom"] >> margin;
setMarginBottom(margin);
}
if(node.FindValue("anchors.left"))
loadAnchor(ANCHOR_LEFT, node["anchors.left"]);
if(node.FindValue("anchors.right"))
loadAnchor(ANCHOR_RIGHT, node["anchors.right"]);
if(node.FindValue("anchors.top"))
loadAnchor(ANCHOR_TOP, node["anchors.top"]);
if(node.FindValue("anchors.bottom"))
loadAnchor(ANCHOR_BOTTOM, node["anchors.bottom"]);
if(node.FindValue("anchors.horizontalCenter"))
loadAnchor(ANCHOR_HORIZONTAL_CENTER, node["anchors.horizontalCenter"]);
if(node.FindValue("anchors.verticalCenter"))
loadAnchor(ANCHOR_VERTICAL_CENTER, node["anchors.verticalCenter"]);
}
void UIElement::loadAnchor(EAnchorType type, const YAML::Node& node)
{
std::string anchorDescription;
node >> anchorDescription;
std::vector<std::string> split;
boost::split(split, anchorDescription, boost::is_any_of("."));
if(split.size() != 2) {
logError("wrong anchors description: %s", anchorDescription.c_str());
return;
}
std::string relativeElementId = split[0];
std::string relativeAnchorTypeId = split[1];
EAnchorType relativeAnchorType;
if(relativeAnchorTypeId == "left")
relativeAnchorType = ANCHOR_LEFT;
else if(relativeAnchorTypeId == "right")
relativeAnchorType = ANCHOR_RIGHT;
else if(relativeAnchorTypeId == "top")
relativeAnchorType = ANCHOR_TOP;
else if(relativeAnchorTypeId == "bottom")
relativeAnchorType = ANCHOR_BOTTOM;
else if(relativeAnchorTypeId == "horizontalCenter")
relativeAnchorType = ANCHOR_HORIZONTAL_CENTER;
else if(relativeAnchorTypeId == "verticalCenter")
relativeAnchorType = ANCHOR_VERTICAL_CENTER;
else {
logError("wrong anchors description: %s", anchorDescription.c_str());
return;
}
AnchorLayoutPtr relativeElement;
if(relativeElementId == "parent" && getParent()) {
relativeElement = getParent()->asAnchorLayout();
} else {
UIElementPtr element = g_ui->recursiveGetChildById(relativeElementId);
if(element)
relativeElement = element->asAnchorLayout();
}
if(relativeElement) {
addAnchor(type, AnchorLine(relativeElement, relativeAnchorType));
} else {
logError("anchoring has failed: %s", anchorDescription.c_str());
return;
}
}
bool UIElement::setSkin(const std::string& skinName) bool UIElement::setSkin(const std::string& skinName)
{ {
setSkin(g_uiSkins.getElementSkin(m_type, skinName)); setSkin(g_uiSkins.getElementSkin(m_type, skinName));

View File

@ -28,7 +28,7 @@
#include "prerequisites.h" #include "prerequisites.h"
#include "core/input.h" #include "core/input.h"
#include "uiconstants.h" #include "uiconstants.h"
#include "anchorlayout.h" #include "uilayout.h"
class UIElementSkin; class UIElementSkin;
@ -40,7 +40,7 @@ class UIElement;
typedef std::shared_ptr<UIElement> UIElementPtr; typedef std::shared_ptr<UIElement> UIElementPtr;
typedef std::weak_ptr<UIElement> UIElementWeakPtr; typedef std::weak_ptr<UIElement> UIElementWeakPtr;
class UIElement : public AnchorLayout class UIElement : public UILayout
{ {
public: public:
UIElement(UI::EElementType type = UI::Element); UIElement(UI::EElementType type = UI::Element);
@ -49,9 +49,6 @@ public:
virtual void render(); virtual void render();
virtual bool onInputEvent(const InputEvent& event) { return false; } virtual bool onInputEvent(const InputEvent& event) { return false; }
virtual void load(const YAML::Node& node);
void loadAnchor(EAnchorType type, const YAML::Node& node);
bool setSkin(const std::string& skinName); bool setSkin(const std::string& skinName);
void setSkin(UIElementSkin *skin); void setSkin(UIElementSkin *skin);
UIElementSkin *getSkin() { return m_skin; } UIElementSkin *getSkin() { return m_skin; }

View File

@ -35,15 +35,6 @@ UILabel::UILabel(const std::string& text, Font* font) :
setSize(m_font->calculateTextRectSize(text)); setSize(m_font->calculateTextRectSize(text));
} }
void UILabel::load(const YAML::Node& node)
{
UIElement::load(node);
std::string text;
node["text"] >> text;
setText(text);
}
void UILabel::render() void UILabel::render()
{ {
m_font->renderText(m_text, getRect(), ALIGN_LEFT, Color(0xFFBFBFBF)); m_font->renderText(m_text, getRect(), ALIGN_LEFT, Color(0xFFBFBFBF));

View File

@ -35,8 +35,6 @@ class UILabel : public UIElement
public: public:
UILabel(const std::string& text = std::string(), Font *font = NULL); UILabel(const std::string& text = std::string(), Font *font = NULL);
void load(const YAML::Node& node);
void render(); void render();
void setText(const std::string& text); void setText(const std::string& text);

View File

@ -22,12 +22,12 @@
*/ */
#include "anchorlayout.h" #include "uilayout.h"
#include "uielement.h" #include "uielement.h"
int AnchorLine::getPos() const int AnchorLine::getPos() const
{ {
AnchorLayoutPtr element = m_relativeElement.lock(); UILayoutPtr element = m_relativeElement.lock();
if(element) { if(element) {
switch(m_anchorType) { switch(m_anchorType) {
case ANCHOR_LEFT: case ANCHOR_LEFT:
@ -50,30 +50,30 @@ int AnchorLine::getPos() const
return 0; return 0;
} }
void AnchorLayout::setSize(const Size& size) void UILayout::setSize(const Size& size)
{ {
m_rect.setSize(size); m_rect.setSize(size);
recalculateAnchors(); recalculateAnchors();
} }
void AnchorLayout::setRect(const Rect& rect) void UILayout::setRect(const Rect& rect)
{ {
m_rect = rect; m_rect = rect;
recalculateAnchors(); recalculateAnchors();
} }
void AnchorLayout::addAnchor(EAnchorType type, const AnchorLine& anchorLine) void UILayout::addAnchor(EAnchorType type, const AnchorLine& anchorLine)
{ {
if(!anchorLine.isValid()) { if(!anchorLine.isValid()) {
logError("anchoring for an element has failed, got an invalid anchor line"); logError("anchoring for an element has failed, got an invalid anchor line");
return; return;
} }
m_anchors[type] = anchorLine; m_anchors[type] = anchorLine;
anchorLine.getRelativeElement()->addAnchoredElement(asAnchorLayout()); anchorLine.getRelativeElement()->addAnchoredElement(asUILayout());
recalculateAnchors(); recalculateAnchors();
} }
void AnchorLayout::addAnchoredElement(AnchorLayoutPtr anchoredElement) void UILayout::addAnchoredElement(UILayoutPtr anchoredElement)
{ {
bool found = false; bool found = false;
for(auto it = m_anchoredElements.begin(); it != m_anchoredElements.end(); ++it) { for(auto it = m_anchoredElements.begin(); it != m_anchoredElements.end(); ++it) {
@ -86,7 +86,7 @@ void AnchorLayout::addAnchoredElement(AnchorLayoutPtr anchoredElement)
m_anchoredElements.push_back(anchoredElement); m_anchoredElements.push_back(anchoredElement);
} }
void AnchorLayout::recalculateAnchors() void UILayout::recalculateAnchors()
{ {
// horizontal // horizontal
if(m_anchors[ANCHOR_HORIZONTAL_CENTER].isValid()) { if(m_anchors[ANCHOR_HORIZONTAL_CENTER].isValid()) {
@ -117,7 +117,7 @@ void AnchorLayout::recalculateAnchors()
} }
for(auto it = m_anchoredElements.begin(); it != m_anchoredElements.end(); ++it) { for(auto it = m_anchoredElements.begin(); it != m_anchoredElements.end(); ++it) {
AnchorLayoutPtr element = (*it).lock(); UILayoutPtr element = (*it).lock();
if(element) if(element)
element->recalculateAnchors(); element->recalculateAnchors();
} }

120
src/framework/ui/uilayout.h Normal file
View File

@ -0,0 +1,120 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef UILAYOUT_H
#define UILAYOUT_H
#include "prerequisites.h"
#include "uiconstants.h"
enum EAnchorType {
ANCHOR_LEFT = 0,
ANCHOR_RIGHT,
ANCHOR_TOP,
ANCHOR_BOTTOM,
ANCHOR_HORIZONTAL_CENTER,
ANCHOR_VERTICAL_CENTER,
ANCHOR_NONE
};
class UILayout;
typedef std::shared_ptr<UILayout> UILayoutPtr;
typedef std::weak_ptr<UILayout> UILayoutWeakPtr;
class AnchorLine
{
public:
AnchorLine() : m_anchorType(ANCHOR_NONE) { }
AnchorLine(const AnchorLine& other) :
m_relativeElement(other.m_relativeElement), m_anchorType(other.m_anchorType) { }
AnchorLine(UILayoutPtr relativeElement, EAnchorType anchorType) :
m_relativeElement(relativeElement), m_anchorType(anchorType) { }
bool isValid() const { return (m_anchorType != ANCHOR_NONE && !m_relativeElement.expired()); }
int getPos() const;
EAnchorType getAnchorType() const { return m_anchorType; }
UILayoutPtr getRelativeElement() const { return m_relativeElement.lock(); }
private:
UILayoutWeakPtr m_relativeElement;
EAnchorType m_anchorType;
};
class UILayout : public std::enable_shared_from_this<UILayout>
{
public:
UILayout() :
m_marginLeft(0),
m_marginRight(0),
m_marginTop(0),
m_marginBottom(0) { }
virtual ~UILayout() { }
void setSize(const Size& size);
Size getSize() { return m_rect.size(); }
void setRect(const Rect& rect);
const Rect& getRect() const{ return m_rect; }
void addAnchor(EAnchorType type, const AnchorLine& anchorLine);
void anchorLeft(const AnchorLine& anchorLine) { addAnchor(ANCHOR_LEFT, anchorLine); }
void anchorRight(const AnchorLine& anchorLine) { addAnchor(ANCHOR_RIGHT, anchorLine); }
void anchorTop(const AnchorLine& anchorLine) { addAnchor(ANCHOR_TOP, anchorLine); }
void anchorBottom(const AnchorLine& anchorLine) { addAnchor(ANCHOR_BOTTOM, anchorLine); }
void anchorHorizontalCenter(const AnchorLine& anchorLine) { addAnchor(ANCHOR_HORIZONTAL_CENTER, anchorLine); }
void anchorVerticalCenter(const AnchorLine& anchorLine) { addAnchor(ANCHOR_VERTICAL_CENTER, anchorLine); }
AnchorLine left() { return AnchorLine(asUILayout(), ANCHOR_LEFT); }
AnchorLine right() { return AnchorLine(asUILayout(), ANCHOR_RIGHT); }
AnchorLine top() { return AnchorLine(asUILayout(), ANCHOR_TOP); }
AnchorLine bottom() { return AnchorLine(asUILayout(), ANCHOR_BOTTOM); }
AnchorLine horizontalCenter() { return AnchorLine(asUILayout(), ANCHOR_HORIZONTAL_CENTER); }
AnchorLine verticalCenter() { return AnchorLine(asUILayout(), ANCHOR_VERTICAL_CENTER); }
void setMargin(int top, int left, int bottom, int right) { m_marginLeft = left; m_marginRight = right; m_marginTop = top; m_marginBottom = bottom; recalculateAnchors(); }
void setMargin(int horizontal, int vertical) { m_marginLeft = m_marginRight = horizontal; m_marginTop = m_marginBottom = vertical; recalculateAnchors(); }
void setMargin(int margin) { m_marginLeft = m_marginRight = m_marginTop = m_marginBottom = margin; recalculateAnchors(); }
void setMarginLeft(int margin) { m_marginLeft = margin; recalculateAnchors(); }
void setMarginRight(int margin) { m_marginRight = margin; recalculateAnchors(); }
void setMarginTop(int margin) { m_marginTop = margin; recalculateAnchors(); }
void setMarginBottom(int margin) { m_marginBottom = margin; recalculateAnchors(); }
UILayoutPtr asUILayout() { return shared_from_this(); }
private:
void recalculateAnchors();
void addAnchoredElement(UILayoutPtr anchoredElement);
AnchorLine m_anchors[6];
Rect m_rect;
int m_marginLeft;
int m_marginRight;
int m_marginTop;
int m_marginBottom;
std::list<UILayoutWeakPtr> m_anchoredElements;
};
#endif // UILAYOUT_H

View File

@ -0,0 +1,254 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "uiloader.h"
#include "core/resources.h"
#include "ui.h"
UIElementPtr UILoader::createElementFromId(const std::string& id)
{
UIElementPtr element;
std::vector<std::string> split;
boost::split(split, id, boost::is_any_of("#"));
if(split.size() != 2)
return element;
std::string elementType = split[0];
std::string elementId = split[1];
if(elementType == "panel") {
element = UIElementPtr(new UIPanel);
} else if(elementType == "button") {
element = UIElementPtr(new UIButton);
} else if(elementType == "label") {
element = UIElementPtr(new UILabel);
} else if(elementType == "window") {
element = UIElementPtr(new UIWindow);
} else if(elementType == "textEdit") {
element = UIElementPtr(new UITextEdit);
}
if(element)
element->setId(elementId);
return element;
}
UIElementPtr UILoader::loadFile(const std::string& file, const UIContainerPtr& parent)
{
std::string fileContents = g_resources.loadTextFile(file);
if(!fileContents.size()) {
logFatal("Could not load ui file \"%s", file.c_str());
return UIElementPtr();
}
std::istringstream fin(fileContents);
try {
YAML::Parser parser(fin);
YAML::Node doc;
parser.GetNextDocument(doc);
// get element id
std::string elementId;
doc.begin().first() >> elementId;
// first we should populate all elements
// only after that we can load anchors
// create element interpreting it's id
UIElementPtr element = createElementFromId(elementId);
if(!element)
throw YAML::Exception(doc.begin().first().GetMark(), "invalid element type");
parent->addChild(element);
// populete it
if(element->asUIContainer())
populateContainer(element->asUIContainer(), doc.begin().second());
// now do the real load
loadElements(element, doc.begin().second());
} catch (YAML::Exception& e) {
logFatal("Failed to load ui file \"%s\":\n %s", file.c_str(), e.what());
}
return UIElementPtr();
}
void UILoader::populateContainer(const UIContainerPtr& parent, const YAML::Node& node)
{
for(auto it = node.begin(); it != node.end(); ++it) {
std::string id;
it.first() >> id;
// check if it's and element id
if(id.find("#") != std::string::npos) {
UIElementPtr element = createElementFromId(id);
if(!element)
throw YAML::Exception(it.first().GetMark(), "invalid element type");
parent->addChild(element);
// also populate this element if it's a parent
if(element->asUIContainer())
populateContainer(element->asUIContainer(), it.second());
}
}
}
void UILoader::loadElements(const UIElementPtr& parent, const YAML::Node& node)
{
loadElement(parent, node);
if(parent->asUIContainer()) {
UIContainerPtr container = parent->asUIContainer();
for(auto it = node.begin(); it != node.end(); ++it) {
std::string id;
it.first() >> id;
// check if it's and element id
if(id.find("#") != std::string::npos) {
std::vector<std::string> split;
boost::split(split, id, boost::is_any_of("#"));
loadElements(container->getChildById(split[1]), it.second());
}
}
}
}
void UILoader::loadElement(const UIElementPtr& element, const YAML::Node& node)
{
std::string tmp;
if(node.FindValue("skin"))
element->setSkin(g_uiSkins.getElementSkin(element->getElementType(), node["skin"]));
if(node.FindValue("size")) {
Size size;
node["size"] >> size;
element->setSize(size);
}
int margin;
if(node.FindValue("margin.left")) {
node["margin.left"] >> margin;
element->setMarginLeft(margin);
}
if(node.FindValue("margin.right")) {
node["margin.right"] >> margin;
element->setMarginRight(margin);
}
if(node.FindValue("margin.top")) {
node["margin.top"] >> margin;
element->setMarginTop(margin);
}
if(node.FindValue("margin.bottom")) {
node["margin.bottom"] >> margin;
element->setMarginBottom(margin);
}
if(node.FindValue("anchors.left"))
loadElementAnchor(element, ANCHOR_LEFT, node["anchors.left"]);
if(node.FindValue("anchors.right"))
loadElementAnchor(element, ANCHOR_RIGHT, node["anchors.right"]);
if(node.FindValue("anchors.top"))
loadElementAnchor(element, ANCHOR_TOP, node["anchors.top"]);
if(node.FindValue("anchors.bottom"))
loadElementAnchor(element, ANCHOR_BOTTOM, node["anchors.bottom"]);
if(node.FindValue("anchors.horizontalCenter"))
loadElementAnchor(element, ANCHOR_HORIZONTAL_CENTER, node["anchors.horizontalCenter"]);
if(node.FindValue("anchors.verticalCenter"))
loadElementAnchor(element, ANCHOR_VERTICAL_CENTER, node["anchors.verticalCenter"]);
// load specific element type
if(element->getElementType() == UI::Button) {
UIButtonPtr button = std::static_pointer_cast<UIButton>(element);
node["text"] >> tmp;
button->setText(tmp);
}
else if(element->getElementType() == UI::Window) {
UIWindowPtr window = std::static_pointer_cast<UIWindow>(element);
node["title"] >> tmp;
window->setTitle(tmp);
}
else if(element->getElementType() == UI::Label) {
UILabelPtr label = std::static_pointer_cast<UILabel>(element);
node["text"] >> tmp;
label->setText(tmp);
}
}
void UILoader::loadElementAnchor(const UIElementPtr& element, EAnchorType type, const YAML::Node& node)
{
std::string anchorDescription;
node >> anchorDescription;
std::vector<std::string> split;
boost::split(split, anchorDescription, boost::is_any_of("."));
if(split.size() != 2)
throw YAML::Exception(node.GetMark(), "invalid anchors description");
std::string relativeElementId = split[0];
std::string relativeAnchorTypeId = split[1];
EAnchorType relativeAnchorType;
if(relativeAnchorTypeId == "left")
relativeAnchorType = ANCHOR_LEFT;
else if(relativeAnchorTypeId == "right")
relativeAnchorType = ANCHOR_RIGHT;
else if(relativeAnchorTypeId == "top")
relativeAnchorType = ANCHOR_TOP;
else if(relativeAnchorTypeId == "bottom")
relativeAnchorType = ANCHOR_BOTTOM;
else if(relativeAnchorTypeId == "horizontalCenter")
relativeAnchorType = ANCHOR_HORIZONTAL_CENTER;
else if(relativeAnchorTypeId == "verticalCenter")
relativeAnchorType = ANCHOR_VERTICAL_CENTER;
else
throw YAML::Exception(node.GetMark(), "invalid anchors description");
UILayoutPtr relativeElement;
if(relativeElementId == "parent" && element->getParent()) {
relativeElement = element->getParent()->asUILayout();
} else {
UIElementPtr tmp = UIContainer::getRootContainer()->recursiveGetChildById(relativeElementId);
if(tmp)
relativeElement = tmp->asUILayout();
}
if(relativeElement) {
element->addAnchor(type, AnchorLine(relativeElement, relativeAnchorType));
} else {
throw YAML::Exception(node.GetMark(), "anchoring failed, does the relative element really exists?");
}
}

View File

@ -0,0 +1,53 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef UILOADER_H
#define UILOADER_H
#include "prerequisites.h"
#include "uiconstants.h"
#include "uicontainer.h"
namespace UILoader
{
/// Detect element type and create it
UIElementPtr createElementFromId(const std::string& id);
/// Loads an UIElement and it's children from a YAML file
UIElementPtr loadFile(const std::string& file, const UIContainerPtr& parent);
/// Populate container children from a YAML node
void populateContainer(const UIContainerPtr& parent, const YAML::Node& node);
/// Load element and its children from a YAML node
void loadElements(const UIElementPtr& parent, const YAML::Node& node);
/// Load element proprieties from a YAML node
void loadElement(const UIElementPtr& element, const YAML::Node& node);
/// Load anchor from a YAML node
void loadElementAnchor(const UIElementPtr& element, EAnchorType type, const YAML::Node& node);
};
#endif // UILOADER_H

View File

@ -23,9 +23,3 @@
#include "uiwindow.h" #include "uiwindow.h"
void UIWindow::load(const YAML::Node& node)
{
UIContainer::load(node);
node["title"] >> m_title;
}

View File

@ -35,8 +35,7 @@ public:
UIContainer(UI::Window), UIContainer(UI::Window),
m_title(title) { } m_title(title) { }
void load(const YAML::Node& node); void setTitle(const std::string& title) { m_title = title; }
const std::string& getTitle() const { return m_title; } const std::string& getTitle() const { return m_title; }
private: private:

View File

@ -0,0 +1,33 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "color.h"
Color Color::white(0xFF, 0xFF, 0xFF, 0xFF);
Color Color::black(0x00, 0x00, 0x00, 0xFF);
Color Color::alpha(0x00, 0x00, 0x00, 0x00);
Color Color::red (0xFF, 0x00, 0x00, 0xFF);
Color Color::green(0x00, 0xFF, 0x00, 0xFF);
Color Color::blue (0x00, 0x00, 0xFF, 0xFF);
Color Color::pink (0xFF, 0x00, 0xFF, 0xFF);

View File

@ -37,10 +37,10 @@ public:
inline Color(const Color& other) : color(other.color) { } inline Color(const Color& other) : color(other.color) { }
inline Color(RGBA rgba) : color(rgba) { } inline Color(RGBA rgba) : color(rgba) { }
inline uint8 red() const { return (color >> 24) & 0xFF; } inline uint8 r() const { return (color >> 24) & 0xFF; }
inline uint8 green() const { return (color >> 16) & 0xFF; } inline uint8 g() const { return (color >> 16) & 0xFF; }
inline uint8 blue() const { return (color >> 8) & 0xFF; } inline uint8 b() const { return (color >> 8) & 0xFF; }
inline uint8 alpha() const { return color & 0xFF; } inline uint8 a() const { return color & 0xFF; }
inline RGBA rgba() const { return color; } inline RGBA rgba() const { return color; }
inline const uint8* rgbaPtr() const { return (const uint8*)&color; } inline const uint8* rgbaPtr() const { return (const uint8*)&color; }
@ -55,6 +55,14 @@ public:
inline bool operator==(const Color& other) const { return other.color == color; } inline bool operator==(const Color& other) const { return other.color == color; }
inline bool operator!=(const Color& other) const { return other.color != color; } inline bool operator!=(const Color& other) const { return other.color != color; }
static Color white;
static Color black;
static Color alpha;
static Color red;
static Color green;
static Color blue;
static Color pink;
private: private:
RGBA color; RGBA color;
}; };
@ -69,4 +77,13 @@ inline void operator>>(const YAML::Node& node, Color& color)
color.setRGBA(r,g,b,a); color.setRGBA(r,g,b,a);
} }
inline std::ostream& operator<<(std::ostream& out, const Color& color)
{
out << "Color(" << (int)color.r() << ","
<< (int)color.g() << ","
<< (int)color.b() << ","
<< (int)color.a() << ")";
return out;
}
#endif // COLOR_H #endif // COLOR_H

View File

@ -85,4 +85,12 @@ inline void operator>>(const YAML::Node& node, TPoint<T>& point)
node[1] >> point.y; node[1] >> point.y;
} }
template <class T>
inline std::ostream& operator<<(std::ostream& out, const TPoint<T>& point)
{
out << "Point(" << point.x << ","
<< point.y << ")";
return out;
}
#endif #endif

View File

@ -304,4 +304,14 @@ inline void operator>>(const YAML::Node& node, TRect<T>& rect)
rect.setRect(x, y, width, height); rect.setRect(x, y, width, height);
} }
template <class T>
inline std::ostream& operator<<(std::ostream& out, const TRect<T>& rect)
{
out << "Rect(" << rect.left() << ","
<< rect.top() << ","
<< rect.width() << ","
<< rect.height() << ")";
return out;
}
#endif // RECT_H #endif // RECT_H

View File

@ -120,4 +120,12 @@ inline void operator>>(const YAML::Node& node, TSize<T>& size)
size.setSize(w, h); size.setSize(w, h);
} }
template <class T>
inline std::ostream& operator<<(std::ostream& out, const TSize<T>& size)
{
out << "Size(" << size.width() << ","
<< size.height() << ")";
return out;
}
#endif #endif

View File

@ -39,15 +39,15 @@ void MenuState::onEnter()
m_background = g_textures.get("background.png"); m_background = g_textures.get("background.png");
m_background->enableBilinearFilter(); m_background->enableBilinearFilter();
UIContainerPtr mainMenuPanel = UIContainer::load("ui/mainMenu-panel.yml"); UIElementPtr mainMenuPanel = UILoader::loadFile("ui/mainMenu.yml", UIContainer::getRootContainer());
/*
UIButtonPtr button = std::static_pointer_cast<UIButton>(mainMenuPanel->getChildById("exitGame-button")); UIButtonPtr button = std::static_pointer_cast<UIButton>(mainMenuPanel->getChildById("exitGame-button"));
button->onClick([]{ g_engine.stop(); }); button->onClick([]{ g_engine.stop(); });
button = std::static_pointer_cast<UIButton>(mainMenuPanel->getChildById("enterGame-button")); button = std::static_pointer_cast<UIButton>(mainMenuPanel->getChildById("enterGame-button"));
button->onClick([]{ button->onClick([]{
UIContainer::load("ui/enterGame-window.yml"); UIContainer::load("ui/enterGame-window.yml");
}); });*/
} }
void MenuState::onLeave() void MenuState::onLeave()
@ -82,7 +82,7 @@ void MenuState::render()
texCoordsSize = texCoordsSize.boundedTo(texSize); texCoordsSize = texCoordsSize.boundedTo(texSize);
Rect texCoords(0, 0, texCoordsSize); Rect texCoords(0, 0, texCoordsSize);
texCoords.moveBottomRight(texSize.toPoint()); texCoords.moveBottomRight(texSize.toPoint());
g_graphics.drawTexturedRect(Rect(0, 0, screenSize), m_background.get(), texCoords); g_graphics.drawTexturedRect(Rect(0, 0, screenSize), m_background, texCoords);
} }
void MenuState::createMainMenu() void MenuState::createMainMenu()