master
Andre Antunes 13 years ago
commit 0b0a62b351

@ -78,13 +78,19 @@ SET(SOURCES
src/framework/util.cpp
# ui
src/framework/ui/anchorlayout.cpp
src/framework/ui/uielement.cpp
src/framework/ui/uielementskin.cpp
src/framework/ui/uibuttonskin.cpp
src/framework/ui/uicontainer.cpp
src/framework/ui/uiskins.cpp
src/framework/ui/uipanel.cpp
src/framework/ui/uibutton.cpp
src/framework/ui/uilabel.cpp
src/framework/ui/uiwindow.cpp
src/framework/ui/uiwindowskin.cpp
src/framework/ui/uitextedit.cpp
src/framework/ui/uitexteditskin.cpp
# network
src/framework/net/connection.cpp

@ -76,8 +76,8 @@ void BorderedImage::setTexCoords(const Rect& left,
m_bottomRightCornerTexCoords = bottomRight;
m_centerTexCoords = center;
m_cornersSize = Size(topLeft.width() + topRight.width(),
topLeft.height() + bottomLeft.height());
m_cornersSize = Size(left.width() + right.width(),
top.height() + bottom.height());
}
void BorderedImage::draw(const Rect& screenCoords)
@ -93,7 +93,8 @@ void BorderedImage::draw(const Rect& screenCoords)
g_graphics._beginTextureRender(m_texture.get());
// first the center
rectCoords = Rect(screenCoords.topLeft() + m_topLeftCornerTexCoords.size().toPoint(),
rectCoords = Rect(screenCoords.left() + m_leftBorderTexCoords.width(),
screenCoords.top() + m_topBorderTexCoords.height(),
centerSize);
g_graphics._drawRepeatedTexturedRect(rectCoords, m_centerTexCoords, textureSize);
@ -124,7 +125,7 @@ void BorderedImage::draw(const Rect& screenCoords)
g_graphics._drawRepeatedTexturedRect(rectCoords, m_leftBorderTexCoords, textureSize);
// right
rectCoords = Rect(screenCoords.left() + m_topLeftCornerTexCoords.width() + centerSize.width(),
rectCoords = Rect(screenCoords.left() + m_leftBorderTexCoords.width() + centerSize.width(),
screenCoords.top() + m_topRightCornerTexCoords.height(),
m_rightBorderTexCoords.width(),
centerSize.height());
@ -132,7 +133,7 @@ void BorderedImage::draw(const Rect& screenCoords)
// bottom left corner
rectCoords = Rect(screenCoords.left(),
screenCoords.top() + m_topLeftCornerTexCoords.height() + centerSize.height(),
screenCoords.top() + m_topBorderTexCoords.height() + centerSize.height(),
m_bottomLeftCornerTexCoords.size());
g_graphics._drawTexturedRect(rectCoords, m_bottomLeftCornerTexCoords, textureSize);
@ -149,5 +150,6 @@ void BorderedImage::draw(const Rect& screenCoords)
m_bottomRightCornerTexCoords.size());
g_graphics._drawTexturedRect(rectCoords, m_bottomRightCornerTexCoords, textureSize);
//g_graphics._drawBoundingRect(screenCoords, Color(0xFF00FF00), 1);
g_graphics._endTextureRender();
}

@ -33,8 +33,6 @@
#include "net/connections.h"
#include "ui/uicontainer.h"
#define MINIMUN_UPDATE_DELAY 50
Engine g_engine;
void Engine::init()
@ -57,17 +55,11 @@ void Engine::terminate()
void Engine::run()
{
int ticks = Platform::getTicks();
int lastUpdateTicks = ticks;
int lastFpsTicks = ticks;
int updateElapsedTicks = ticks;
int frameCount = 0;
int fps = 0;
m_running = true;
// before redering do the first update
update(ticks, 0);
lastUpdateTicks = ticks;
while(!m_stopping) {
// poll platform events
Platform::poll();
@ -75,18 +67,11 @@ void Engine::run()
// poll network events
g_connections.poll();
// update before redering
ticks = Platform::getTicks();
// poll diaptcher tasks
g_dispatcher.poll(ticks);
updateElapsedTicks = ticks - lastUpdateTicks;
if(updateElapsedTicks >= MINIMUN_UPDATE_DELAY) {
update(ticks, updateElapsedTicks);
lastUpdateTicks = ticks;
}
// render only when visible
if(Platform::isWindowVisible()) {
// calculate and fps
@ -140,13 +125,6 @@ void Engine::render()
g_graphics.endRender();
}
void Engine::update(int ticks, int elapsedTicks)
{
if(m_currentState)
m_currentState->update(ticks, elapsedTicks);
g_ui->update(ticks, elapsedTicks);
}
void Engine::onClose()
{
if(m_currentState)
@ -156,13 +134,13 @@ void Engine::onClose()
void Engine::onResize(const Size& size)
{
g_graphics.resize(size);
g_ui->resize(size);
g_ui->setSize(size);
if(m_currentState)
m_currentState->onResize(size);
}
void Engine::onInputEvent(InputEvent *event)
void Engine::onInputEvent(const InputEvent& event)
{
// inputs goest to gui first
if(!g_ui->onInputEvent(event)) {

@ -60,7 +60,7 @@ public:
/// Fired by platform on window resize
void onResize(const Size& size);
/// Fired by platform on mouse/keyboard input
void onInputEvent(InputEvent *event);
void onInputEvent(const InputEvent& event);
/// Enable FPS counter on screen
void enableFpsCounter(bool enable = true) { m_calculateFps = enable; };
@ -68,8 +68,6 @@ public:
private:
/// Called to render every frame
void render();
/// Called between renders
void update(int ticks, int elapsedTicks);
bool m_stopping;
bool m_running;

@ -28,12 +28,47 @@
#include "graphics.h"
Font::Font() :
m_lineHeight(14),
m_cursorSize(14),
m_color(0xFFFFFFFF)
m_glyphHeight(10),
m_topMargin(0)
{
}
void Font::calculateGlyphsWidthsAutomatically(const Size& glyphSize)
{
int numHorizontalGlyphs = m_texture->getSize().width() / glyphSize.width();
uchar *texturePixels = m_texture->getPixels();
// small AI to auto calculate pixels widths
for(int glyph = 32; glyph< 256; ++glyph) {
Rect glyphCoords(((glyph - 32) % numHorizontalGlyphs) * glyphSize.width(),
((glyph - 32) / numHorizontalGlyphs) * glyphSize.height(),
glyphSize.width(),
m_glyphHeight);
int width = glyphSize.width();
for(int x = glyphCoords.left() + 2; x <= glyphCoords.right(); ++x) {
bool allAlpha = true;
// check if all vertical pixels are alpha
for(int y = glyphCoords.top(); y <= glyphCoords.bottom(); ++y) {
if(texturePixels[(y * m_texture->getSize().width() * 4) + (x*4) + 3] != 0) {
allAlpha = false;
break;
}
}
// if all pixels were alpha we found the width
if(allAlpha) {
width = x - glyphCoords.left();
break;
}
}
// store glyph size
m_glyphsSize[glyph].setSize(width, m_glyphHeight);
}
delete[] texturePixels;
}
bool Font::load(const std::string& file)
{
std::string fileContents = g_resources.loadTextFile(file);
@ -45,10 +80,7 @@ bool Font::load(const std::string& file)
std::istringstream fin(fileContents);
std::string textureName;
int numHorizontalGlyphs;
int firstGlyph;
Size glyphSize;
Size textureSize;
try {
YAML::Parser parser(fin);
@ -56,10 +88,9 @@ bool Font::load(const std::string& file)
YAML::Node doc;
parser.GetNextDocument(doc);
doc["line height"] >> m_lineHeight;
doc["cursor size"] >> m_cursorSize;
doc["color"] >> m_color;
doc["first glyph"] >> firstGlyph;
doc["glyph height"] >> m_glyphHeight;
doc["glyph spacing"] >> m_glyphSpacing;
doc["top margin"] >> m_topMargin;
doc["image glyph size"] >> glyphSize;
doc["image"] >> textureName;
@ -69,25 +100,32 @@ bool Font::load(const std::string& file)
return false;
}
textureSize = m_texture->getSize();
numHorizontalGlyphs = textureSize.width() / glyphSize.width();
// set glyphs height
for(int glyph = 32; glyph < 256; ++glyph) {
}
const YAML::Node& widthsNode = doc["glyph widths"];
for(auto it = widthsNode.begin(); it != widthsNode.end(); ++it) {
int glyph, glyphWidth;
it.first() >> glyph;
it.second() >> glyphWidth;
calculateGlyphsWidthsAutomatically(glyphSize);
// calculate glyph texture coords
m_glyphsTextureCoords[glyph].setRect(((glyph - firstGlyph) % numHorizontalGlyphs) * glyphSize.width(),
((glyph - firstGlyph) / numHorizontalGlyphs) * glyphSize.height(),
glyphWidth,
glyphSize.height());
// read custom widths
if(doc.FindValue("glyph widths")) {
const YAML::Node& widthsNode = doc["glyph widths"];
for(auto it = widthsNode.begin(); it != widthsNode.end(); ++it) {
int glyph, glyphWidth;
it.first() >> glyph;
it.second() >> glyphWidth;
m_glyphsSize[glyph].setWidth(glyphWidth);
}
}
// store glyph size
m_glyphsSize[glyph].setHeight(glyphSize.height());
m_glyphsSize[glyph].setWidth(glyphWidth);
// calculate glyphs texture coords
int numHorizontalGlyphs = m_texture->getSize().width() / glyphSize.width();
for(int glyph = 32; glyph< 256; ++glyph) {
m_glyphsTextureCoords[glyph].setRect(((glyph - 32) % numHorizontalGlyphs) * glyphSize.width(),
((glyph - 32) / numHorizontalGlyphs) * glyphSize.height(),
m_glyphsSize[glyph].width(),
m_glyphHeight);
}
} catch (YAML::ParserException& e) {
logError("Malformed font file \"%s\"", file.c_str());
return false;
@ -107,6 +145,7 @@ void Font::renderText(const std::string& text,
void Font::renderText(const std::string& text,
const Rect& screenCoords,
int align,
const Color& color,
const Point& startInternalPos,
bool debug)
{
@ -115,7 +154,7 @@ void Font::renderText(const std::string& text,
return;
// begin texture rendering
g_graphics.setColor(m_color);
g_graphics.setColor(color);
g_graphics._beginTextureRender(m_texture.get());
const Size& textureSize = m_texture->getSize();
@ -189,6 +228,8 @@ void Font::renderText(const std::string& text,
// render glyph
g_graphics._drawTexturedRect(glyphScreenCoords, glyphTextureCoords, textureSize);
//g_graphics._drawBoundingRect(glyphScreenCoords, Color(0xFF0000FF));
}
// end texture redering
@ -196,7 +237,7 @@ void Font::renderText(const std::string& text,
g_graphics.resetColor();
if(debug)
g_graphics.drawBoundingRect(screenCoords.expanded(1), Color(0xFF00FF00), 1);
g_graphics.drawBoundingRect(screenCoords.expanded(1), Color(0xFF00FF00));
}
Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size *textBoxSize)
@ -211,7 +252,7 @@ Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size *
// protect buffer overflow on glyphsPostions
int numGlyphs = text.length();
if(numGlyphs > 8192)
logFatal("A text was too long to render!");
logFatal("could not calculate glyphs positions, text length is > 8192!");
// calculate lines width
if((align & ALIGN_RIGHT || align & ALIGN_HORIZONTAL_CENTER) || textBoxSize) {
@ -222,13 +263,13 @@ Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size *
if(glyph == (uchar)'\n') {
lineWidths[++lines] = 0;
} else if(glyph >= 32) {
lineWidths[lines] += m_glyphsSize[glyph].width();
lineWidths[lines] += m_glyphsSize[glyph].width() + m_glyphSpacing.width();
maxLineWidth = std::max(maxLineWidth, lineWidths[lines]);
}
}
}
Point virtualPos;
Point virtualPos(0, m_topMargin);
lines = 0;
for(i = 0; i < numGlyphs; ++i) {
glyph = (int)text[i];
@ -239,7 +280,7 @@ Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size *
// new line or first glyph
if(glyph == (uchar)'\n' || i == 0) {
if(glyph == (uchar)'\n') {
virtualPos.y += m_lineHeight;
virtualPos.y += m_glyphHeight + m_glyphSpacing.height();
lines++;
}
@ -255,13 +296,13 @@ Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size *
// render only if the glyph is valid
if(glyph >= 32 && glyph != (uchar)'\n') {
virtualPos.x += m_glyphsSize[glyph].width();
virtualPos.x += m_glyphsSize[glyph].width() + m_glyphSpacing.width();
}
}
if(textBoxSize) {
textBoxSize->setWidth(maxLineWidth);
textBoxSize->setHeight(virtualPos.y + m_lineHeight);
textBoxSize->setHeight(virtualPos.y + m_glyphHeight);
}
return (Point *)glyphsPositions;

@ -64,6 +64,7 @@ public:
void renderText(const std::string& text,
const Rect& screenCoords,
int align = ALIGN_TOP_LEFT,
const Color& color = Color(0xFFFFFFFF),
const Point& startInternalPos = Point(),
bool debug = false);
@ -74,9 +75,11 @@ public:
Size calculateTextRectSize(const std::string& text);
private:
int m_lineHeight;
int m_cursorSize;
Color m_color;
void calculateGlyphsWidthsAutomatically(const Size& glyphSize);
int m_glyphHeight;
int m_topMargin;
Size m_glyphSpacing;
TexturePtr m_texture;
Rect m_glyphsTextureCoords[256];
Size m_glyphsSize[256];

@ -25,6 +25,7 @@
#ifndef GAMESTATE_H
#define GAMESTATE_H
#include "input.h"
#include "size.h"
struct InputEvent;
@ -39,11 +40,10 @@ public:
virtual void onLeave() = 0;
virtual void onClose() = 0;
virtual void onInputEvent(InputEvent *event) = 0;
virtual void onInputEvent(const InputEvent& event) = 0;
virtual void onResize(const Size& size) = 0;
virtual void render() = 0;
virtual void update(int ticks, int elapsedTicks) = 0;
};
#endif // GAMESTATE_H

@ -148,6 +148,9 @@ void Graphics::_endTextureRender()
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());
@ -156,6 +159,9 @@ void Graphics::drawTexturedRect(const Rect& screenCoords, const Texture *texture
void Graphics::_drawTexturedRect(const Rect& screenCoords, const Rect& textureCoords, const Size& textureSize)
{
if(screenCoords.size().isEmpty())
return;
// rect correction for opengl
int right = screenCoords.right() + 1;
int bottom = screenCoords.bottom() + 1;
@ -182,6 +188,9 @@ void Graphics::_drawTexturedRect(const Rect& screenCoords, const Rect& textureCo
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());
@ -190,6 +199,9 @@ void Graphics::drawRepeatedTexturedRect(const Rect& screenCoords, const Texture*
void Graphics::_drawRepeatedTexturedRect(const Rect& screenCoords, const Rect& textureCoords, const Size& textureSize)
{
if(screenCoords.size().isEmpty())
return;
// render many repeated texture rects
Rect virtualScreenCoords(0,0,screenCoords.size());
for(int y = 0; y <= virtualScreenCoords.height(); y += textureCoords.height()) {
@ -216,6 +228,9 @@ void Graphics::_drawRepeatedTexturedRect(const Rect& screenCoords, const Rect& t
void Graphics::drawColoredRect(const Rect& screenCoords, const Color& color)
{
if(screenCoords.size().isEmpty())
return;
glDisable(GL_TEXTURE_2D);
setColor(color);

@ -25,6 +25,8 @@
#ifndef INPUT_H
#define INPUT_H
#include "prerequisites.h"
enum EKeyCode {
KC_UNKNOWN = 0x00,
KC_ESCAPE = 0x01,

@ -72,7 +72,7 @@ namespace Platform
void swapBuffers();
/// Get the app user directory, the place to save files configurations files
const char *getAppUserDir();
std::string getAppUserDir();
}
#endif // PLATFORM_H

@ -54,6 +54,8 @@ public:
inline T top() const { return y1; }
inline T right() const { return x2; }
inline T bottom() const { return y2; }
inline T horizontalCenter() const { return x1 + (x2 - x1)/2; }
inline T verticalCenter() const { return y1 + (y2 - y1)/2; }
inline T x() const { return x1; }
inline T y() const { return y1; }
inline TPoint<T> topLeft() const { return TPoint<T>(x1, y1); }
@ -108,6 +110,16 @@ public:
x2 = x1 + w;
y2 = y1 + h;
}
inline void moveHorizontalCenter(T x) {
T w = x2 - x1;
x1 = x - w/2;
x2 = x1 + w;
}
inline void moveVerticalCenter(T y) {
T h = y2 - y1;
y1 = y - h/2;
y2 = y1 + h;
}
inline bool contains(const TPoint<T> &p, bool insideOnly = false) const {
T l, r;

@ -72,3 +72,11 @@ void Texture::enableBilinearFilter()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
uchar *Texture::getPixels()
{
uchar *pixels = new uchar[m_size.area()*4];
glBindTexture(GL_TEXTURE_2D, m_textureId);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
return pixels;
}

@ -42,6 +42,7 @@ public:
const Size& getSize() const { return m_size; }
uint getTextureId() const { return m_textureId; }
uchar *getPixels();
private:
uint m_textureId;

@ -0,0 +1,123 @@
/* 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 "anchorlayout.h"
int AnchorLine::getPos() const
{
AnchorLayoutPtr element = m_relativeElement.lock();
if(element) {
switch(m_anchorType) {
case ANCHOR_LEFT:
return element->getRect().left();
case ANCHOR_RIGHT:
return element->getRect().right();
case ANCHOR_TOP:
return element->getRect().top();
case ANCHOR_BOTTOM:
return element->getRect().bottom();
case ANCHOR_HORIZONTAL_CENTER:
return element->getRect().horizontalCenter();
case ANCHOR_VERTICAL_CENTER:
return element->getRect().verticalCenter();
default:
return 0;
}
}
logError("anchor line of an element have expired");
return 0;
}
void AnchorLayout::setSize(const Size& size)
{
m_rect.setSize(size);
recalculateAnchors();
}
void AnchorLayout::setRect(const Rect& rect)
{
m_rect = rect;
recalculateAnchors();
}
void AnchorLayout::addAnchor(EAnchorType type, const AnchorLine& anchorLine)
{
if(!anchorLine.isValid()) {
logError("anchoring for an element has failed, got an invalid anchor line");
return;
}
m_anchors[type] = anchorLine;
anchorLine.getRelativeElement()->addAnchoredElement(asAnchorLayout());
recalculateAnchors();
}
void AnchorLayout::addAnchoredElement(AnchorLayoutPtr anchoredElement)
{
bool found = false;
for(auto it = m_anchoredElements.begin(); it != m_anchoredElements.end(); ++it) {
if((*it).lock() == anchoredElement) {
found = true;
break;
}
}
if(!found)
m_anchoredElements.push_back(anchoredElement);
}
void AnchorLayout::recalculateAnchors()
{
// horizontal
if(m_anchors[ANCHOR_HORIZONTAL_CENTER].isValid()) {
m_rect.moveHorizontalCenter(m_anchors[ANCHOR_HORIZONTAL_CENTER].getPos() + m_marginLeft - m_marginRight);
} else {
if(m_anchors[ANCHOR_LEFT].isValid() && m_anchors[ANCHOR_RIGHT].isValid()) {
m_rect.setLeft(m_anchors[ANCHOR_LEFT].getPos() + m_marginLeft);
m_rect.setRight(m_anchors[ANCHOR_RIGHT].getPos() - m_marginRight);
} else if(m_anchors[ANCHOR_LEFT].isValid()) {
m_rect.moveLeft(m_anchors[ANCHOR_LEFT].getPos() + m_marginLeft);
} else if(m_anchors[ANCHOR_RIGHT].isValid()) {
m_rect.moveRight(m_anchors[ANCHOR_RIGHT].getPos() - m_marginRight);
}
}
// vertical
if(m_anchors[ANCHOR_VERTICAL_CENTER].isValid()) {
m_rect.moveVerticalCenter(m_anchors[ANCHOR_VERTICAL_CENTER].getPos() + m_marginTop - m_marginBottom);
} else {
if(m_anchors[ANCHOR_TOP].isValid() && m_anchors[ANCHOR_BOTTOM].isValid()) {
m_rect.setLeft(m_anchors[ANCHOR_TOP].getPos() + m_marginTop);
m_rect.setRight(m_anchors[ANCHOR_BOTTOM].getPos() - m_marginBottom);
} else if(m_anchors[ANCHOR_TOP].isValid()) {
m_rect.moveTop(m_anchors[ANCHOR_TOP].getPos() + m_marginTop);
} else if(m_anchors[ANCHOR_BOTTOM].isValid()) {
m_rect.moveBottom(m_anchors[ANCHOR_BOTTOM].getPos() - m_marginBottom);
}
}
for(auto it = m_anchoredElements.begin(); it != m_anchoredElements.end(); ++it) {
AnchorLayoutPtr element = (*it).lock();
if(element)
element->recalculateAnchors();
}
}

@ -0,0 +1,116 @@
/* 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 ANCHORLAYOUT_H
#define ANCHORLAYOUT_H
#include "../prerequisites.h"
#include "../rect.h"
#include "uiconstants.h"
enum EAnchorType {
ANCHOR_LEFT = 0,
ANCHOR_RIGHT,
ANCHOR_TOP,
ANCHOR_BOTTOM,
ANCHOR_HORIZONTAL_CENTER,
ANCHOR_VERTICAL_CENTER,
ANCHOR_NONE
};
class AnchorLayout;
typedef std::shared_ptr<AnchorLayout> AnchorLayoutPtr;
typedef std::weak_ptr<AnchorLayout> AnchorLayoutWeakPtr;
class AnchorLine
{
public:
AnchorLine() : m_anchorType(ANCHOR_NONE) { }
AnchorLine(const AnchorLine& other) :
m_relativeElement(other.m_relativeElement), m_anchorType(other.m_anchorType) { }
AnchorLine(AnchorLayoutPtr 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; }
AnchorLayoutPtr getRelativeElement() const { return m_relativeElement.lock(); }
private:
AnchorLayoutWeakPtr m_relativeElement;
EAnchorType m_anchorType;
};
class AnchorLayout : public std::enable_shared_from_this<AnchorLayout>
{
public:
AnchorLayout() :
m_marginLeft(0),
m_marginRight(0),
m_marginTop(0),
m_marginBottom(0) { }
virtual ~AnchorLayout() { }
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(asAnchorLayout(), ANCHOR_LEFT); }
AnchorLine right() { return AnchorLine(asAnchorLayout(), ANCHOR_RIGHT); }
AnchorLine top() { return AnchorLine(asAnchorLayout(), ANCHOR_TOP); }
AnchorLine bottom() { return AnchorLine(asAnchorLayout(), ANCHOR_BOTTOM); }
AnchorLine horizontalCenter() { return AnchorLine(asAnchorLayout(), ANCHOR_HORIZONTAL_CENTER); }
AnchorLine verticalCenter() { return AnchorLine(asAnchorLayout(), 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(); }
AnchorLayoutPtr asAnchorLayout() { return shared_from_this(); }
private:
void recalculateAnchors();
void addAnchoredElement(AnchorLayoutPtr anchoredElement);
AnchorLine m_anchors[6];
Rect m_rect;
int m_marginLeft;
int m_marginRight;
int m_marginTop;
int m_marginBottom;
std::list<AnchorLayoutWeakPtr> m_anchoredElements;
};
#endif // ANCHORLAYOUT_H

@ -29,11 +29,12 @@
#include "uiconstants.h"
#include "uielement.h"
#include "uielementskin.h"
#include "uicontainer.h"
#include "uipanel.h"
#include "uibutton.h"
#include "uilabel.h"
#include "uiskins.h"
#include "uiwindow.h"
#include "uitextedit.h"
#endif // UI_H

@ -30,5 +30,20 @@ void UIButton::render()
{
UIElement::render();
g_fonts.get("tibia-8px-antialised")->renderText(m_text, m_rect, ALIGN_CENTER);
g_fonts.get("tibia-8px-antialised")->renderText(m_text, getRect(), ALIGN_CENTER, Color(0xFFEEEEEE));
}
bool UIButton::onInputEvent(const InputEvent& event)
{
if(event.type == EV_MOUSE_LDOWN &&
getRect().contains(Point(event.mouse.x, event.mouse.y))) {
m_state = UI::ButtonDown;
} else if(m_state == UI::ButtonDown && event.type == EV_MOUSE_LUP) {
m_state = UI::ButtonUp;
if(getRect().contains(Point(event.mouse.x, event.mouse.y))) {
if(m_buttonClickCallback)
m_buttonClickCallback();
}
}
return false;
}

@ -29,6 +29,8 @@
#include "uielement.h"
#include "../borderedimage.h"
typedef std::function<void()> Callback;
class UIButton : public UIElement
{
public:
@ -39,10 +41,16 @@ public:
}
virtual void render();
bool onInputEvent(const InputEvent& event);
UI::EButtonState getState() { return m_state; }
void onClick(const Callback& callback) { m_buttonClickCallback = callback; }
private:
std::string m_text;
UI::EButtonState m_state;
Callback m_buttonClickCallback;
};
typedef std::shared_ptr<UIButton> UIButtonPtr;

@ -0,0 +1,50 @@
/* 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 "uibuttonskin.h"
#include "uibutton.h"
void UIButtonSkin::draw(UIElement *element)
{
UIButton *button = static_cast<UIButton*>(element);
if(button->getState() == UI::ButtonDown && m_buttonDownImage) {
m_buttonDownImage->draw(element->getRect());
} else if(button->getState() == UI::ButtonMouseOver && m_buttonHoverImage) {
m_buttonHoverImage->draw(element->getRect());
} else {
UIElementSkin::draw(element);
}
}
void UIButtonSkin::load(const YAML::Node& node)
{
UIElementSkin::load(node);
if(node.FindValue("down state"))
m_buttonDownImage = loadImage(node["down state"]);
if(node.FindValue("mouse over state"))
m_buttonHoverImage = loadImage(node["mouse over state"]);
}

@ -0,0 +1,46 @@
/* 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 UIBUTTONSKIN_H
#define UIBUTTONSKIN_H
#include "../prerequisites.h"
#include "uiconstants.h"
#include "uielementskin.h"
class UIButtonSkin : public UIElementSkin
{
public:
UIButtonSkin(const std::string& name) :
UIElementSkin(name, UI::Button) { }
void load(const YAML::Node& node);
void draw(UIElement *element);
private:
ImagePtr m_buttonDownImage;
ImagePtr m_buttonHoverImage;
};
#endif // UIBUTTONSKIN_H

@ -53,12 +53,12 @@ namespace UI {
enum EElementType
{
Element,
Element = 0,
Container,
Panel,
Window,
Label,
TextBox,
TextEdit,
Button,
CheckBox
};

@ -30,11 +30,6 @@ void UIContainer::addChild(UIElementPtr child)
{
m_children.push_back(child);
child->setParent(asUIContainer());
// adjust child rect
Rect childRect = child->getRect();
childRect.translate(m_rect.topLeft());
child->setRect(childRect);
}
void UIContainer::removeChild(UIElementPtr child)
@ -42,12 +37,14 @@ void UIContainer::removeChild(UIElementPtr child)
if(m_activeElement == child)
setActiveElement(UIElementPtr());
m_children.remove(child);
if(child->getParent() == shared_from_this())
child->setParent(UIContainerPtr());
}
UIElementPtr UIContainer::getChildByName(const std::string& name) const
UIElementPtr UIContainer::getChildById(const std::string& id) const
{
for(auto it = m_children.begin(); it != m_children.end(); ++it) {
if((*it)->getName() == name) {
if((*it)->getId() == id) {
return (*it);
break;
}
@ -55,62 +52,25 @@ UIElementPtr UIContainer::getChildByName(const std::string& name) const
return UIElementPtr();
}
void UIContainer::setRect(const Rect& rect)
void UIContainer::render()
{
// update children rect
UIElement::render();
for(auto it = m_children.begin(); it != m_children.end(); ++it) {
const UIElementPtr& child = (*it);
// transforme child rect
Rect childRect = child->getRect();
childRect.translate(-m_rect.topLeft());
childRect.translate(rect.topLeft());
child->setRect(childRect);
if(child->isVisible())
child->render();
}
m_rect = rect;
}
void UIContainer::resize(const Size& size)
bool UIContainer::onInputEvent(const InputEvent& event)
{
Rect newRect = m_rect;
newRect.setSize(size);
setRect(newRect);
}
void UIContainer::move(const Point& trans)
{
Rect newRect = m_rect;
newRect.translate(trans);
setRect(newRect);
}
void UIContainer::moveTo(const Point& pos)
{
Rect newRect = m_rect;
newRect.moveTo(pos);
setRect(newRect);
}
void UIContainer::render()
{
UIElement::render();
bool ret = false;
for(auto it = m_children.begin(); it != m_children.end(); ++it) {
const UIElementPtr& child = (*it);
child->render();
if(child->isEnabled() && child->isVisible())
ret = child->onInputEvent(event) || ret;
}
}
void UIContainer::update(int ticks, int elapsedTicks)
{
}
bool UIContainer::onInputEvent(InputEvent* event)
{
return false;
return ret;
}
void UIContainer::setActiveElement(UIElementPtr activeElement)

@ -36,20 +36,14 @@ public:
UIContainer(UI::EElementType type = UI::Container) : UIElement(type) { }
virtual ~UIContainer() { }
virtual void addChild(UIElementPtr child);
virtual void removeChild(UIElementPtr child);
virtual UIElementPtr getChildByName(const std::string& name) const;
virtual void setRect(const Rect& rect);
virtual void resize(const Size& size);
virtual void move(const Point& trans);
virtual void moveTo(const Point& pos);
void addChild(UIElementPtr child);
void removeChild(UIElementPtr child);
UIElementPtr getChildById(const std::string& id) const;
virtual void render();
virtual void update(int ticks, int elapsedTicks);
virtual bool onInputEvent(InputEvent *event);
virtual bool onInputEvent(const InputEvent& event);
virtual void setActiveElement(UIElementPtr activeElement);
void setActiveElement(UIElementPtr activeElement);
UIElementPtr getActiveElement() const { return m_activeElement; }
virtual UI::EElementType getElementType() const { return UI::Container; }

@ -24,12 +24,18 @@
#include "uielement.h"
#include "uiskins.h"
#include "uielementskin.h"
UIElement::UIElement(UI::EElementType type) :
m_type(type)
AnchorLayout(),
m_type(type),
m_skin(NULL),
m_visible(true),
m_enabled(true)
{
// set default skin
setSkin(g_uiSkins.getElementSkin(type));
if(type > UI::Container)
setSkin(g_uiSkins.getElementSkin(type));
}
@ -41,8 +47,8 @@ bool UIElement::setSkin(const std::string& skinName)
void UIElement::setSkin(UIElementSkin* skin)
{
if(skin && !m_rect.isValid()) {
m_rect.setSize(skin->getDefaultSize());
if(skin && !getRect().isValid()) {
setSize(skin->getDefaultSize());
}
m_skin = skin;
}
@ -52,4 +58,3 @@ void UIElement::render()
if(m_skin)
m_skin->draw(this);
}

@ -29,55 +29,54 @@
#include "../input.h"
#include "../rect.h"
#include "uiconstants.h"
#include "uielementskin.h"
#include "anchorlayout.h"
class UIElementSkin;
class UIContainer;
typedef std::shared_ptr<UIContainer> UIContainerPtr;
typedef std::weak_ptr<UIContainer> UIContainerWeakPtr;
class UIElement;
typedef std::shared_ptr<UIElement> UIElementPtr;
typedef std::weak_ptr<UIElement> UIElementWeakPtr;
class UIElement : public std::enable_shared_from_this<UIElement>
class UIElement : public AnchorLayout
{
public:
UIElement(UI::EElementType type = UI::Element);
virtual ~UIElement() { }
virtual void render();
virtual void update(int ticks, int elapsedTicks) { }
virtual bool onInputEvent(InputEvent *event) { return false; }
virtual bool onInputEvent(const InputEvent& event) { return false; }
bool setSkin(const std::string& skinName);
void setSkin(UIElementSkin *skin);
UIElementSkin *getSkin() { return m_skin; }
virtual void setParent(UIContainerPtr parent) { m_parent = parent; }
UIContainerPtr getParent() const { return m_parent; }
virtual void setName(const std::string& name) { m_name = name; }
const std::string& getName() const { return m_name; }
UIContainerPtr getParent() const { return m_parent.lock(); }
virtual void setRect(const Rect& rect) { m_rect = rect; }
const Rect& getRect() const{ return m_rect; }
void setId(const std::string& id) { m_id = id; }
const std::string& getId() const { return m_id; }
virtual void setActive(bool active) { m_active = active; }
bool isActive() const { return m_active; }
void setEnabled(bool enabled) { m_enabled = enabled; }
bool isEnabled() const { return m_enabled; }
virtual void setVisible(bool visible) { m_visible = visible; }
void setVisible(bool visible) { m_visible = visible; }
bool isVisible() const { return m_visible; }
UI::EElementType getElementType() const { return m_type; }
UIElementPtr asUIElement() { return shared_from_this(); }
UIElementPtr asUIElement() { return std::static_pointer_cast<UIElement>(shared_from_this()); }
protected:
private:
UI::EElementType m_type;
UIContainerPtr m_parent;
UIContainerWeakPtr m_parent;
UIElementSkin *m_skin;
Rect m_rect;
std::string m_name;
std::string m_id;
bool m_visible;
bool m_active;
bool m_enabled;
};
#endif // UIELEMENT_H

@ -30,29 +30,41 @@
void UIElementSkin::draw(UIElement *element)
{
const ImagePtr& image = m_stateImages.front();
if(image) {
image->draw(element->getRect());
}
if(m_defaultImage)
m_defaultImage->draw(element->getRect());
}
void UIElementSkin::load(const YAML::Node& node)
{
if(node.FindValue("default size"))
node["default size"] >> m_defaultSize;
m_defaultImage = loadImage(node);
}
ImagePtr UIElementSkin::loadImage(const YAML::Node& node)
{
ImagePtr image;
if(node.FindValue("bordered image")) {
const YAML::Node& child = node["bordered image"];
Rect left, right, top, bottom, topLeft, topRight, bottomLeft, bottomRight, center;
child["left border"] >> left;
child["right border"] >> right;
child["top border"] >> top;
child["bottom border"] >> bottom;
child["top left corner"] >> topLeft;
child["top right corner"] >> topRight;
child["bottom left corner"] >> bottomLeft;
child["bottom right corner"] >> bottomRight;
child["center"] >> center;
if(child.FindValue("left border"))
child["left border"] >> left;
if(child.FindValue("right border"))
child["right border"] >> right;
if(child.FindValue("top border"))
child["top border"] >> top;
if(child.FindValue("bottom border"))
child["bottom border"] >> bottom;
if(child.FindValue("top left corner"))
child["top left corner"] >> topLeft;
if(child.FindValue("top right corner"))
child["top right corner"] >> topRight;
if(child.FindValue("bottom left corner"))
child["bottom left corner"] >> bottomLeft;
if(child.FindValue("bottom right corner"))
child["bottom right corner"] >> bottomRight;
if(child.FindValue("center"))
child["center"] >> center;
TexturePtr texture;
if(child.FindValue("image")) {
@ -63,7 +75,7 @@ void UIElementSkin::load(const YAML::Node& node)
texture = g_uiSkins.getDefaultTexture();
}
ImagePtr image = ImagePtr(new BorderedImage(texture,
image = ImagePtr(new BorderedImage(texture,
left,
right,
top,
@ -73,6 +85,7 @@ void UIElementSkin::load(const YAML::Node& node)
bottomLeft,
bottomRight,
center));
m_stateImages.push_back(image);
}
return image;
}

@ -38,19 +38,24 @@ public:
UIElementSkin(const std::string& name, UI::EElementType elementType) :
m_name(name),
m_elementType(elementType) { }
virtual ~UIElementSkin() { }
void load(const YAML::Node& node);
void draw(UIElement *element);
virtual void load(const YAML::Node& node);
virtual void draw(UIElement *element);
const std::string& getName() const { return m_name; }
const Size& getDefaultSize() const { return m_defaultSize; }
UI::EElementType getElementType() const { return m_elementType; }
ImagePtr getDefaultImage() const { return m_defaultImage; }
protected:
ImagePtr loadImage(const YAML::Node& node);
private:
std::string m_name;
UI::EElementType m_elementType;
Size m_defaultSize;
std::vector<ImagePtr> m_stateImages;
ImagePtr m_defaultImage;
};
#endif // UIELEMENTSKIN_H

@ -23,4 +23,26 @@
#include "uilabel.h"
#include "../fonts.h"
UILabel::UILabel(const std::string& text, Font* font) :
UIElement(UI::Label),
m_text(text),
m_font(font)
{
if(!font)
m_font = g_fonts.get("tibia-10px-antialised");
setSize(m_font->calculateTextRectSize(text));
}
void UILabel::render()
{
m_font->renderText(m_text, getRect(), ALIGN_LEFT, Color(0xFFBFBFBF));
}
void UILabel::setText(const std::string& text)
{
setSize(m_font->calculateTextRectSize(text));
m_text = text;
}

@ -28,10 +28,23 @@
#include "../prerequisites.h"
#include "uielement.h"
class Font;
class UILabel : public UIElement
{
public:
UILabel() : UIElement(UI::Label) { }
UILabel(const std::string& text, Font *font = NULL);
void render();
void setText(const std::string& text);
const std::string& getText() const { return m_text; }
private:
std::string m_text;
Font *m_font;
};
typedef std::shared_ptr<UILabel> UILabelPtr;
#endif // UILABEL_H

@ -26,9 +26,26 @@
#include "../resources.h"
#include "../textures.h"
#include "uielementskin.h"
#include "uibuttonskin.h"
#include "uiwindowskin.h"
#include "uitexteditskin.h"
UISkins g_uiSkins;
void UISkins::init()
{
// load default skin
g_uiSkins.load("skins/tibiaskin.yml");
}
void UISkins::terminate()
{
for(auto it = m_elementSkins.begin(); it != m_elementSkins.end(); ++it)
delete (*it);
m_elementSkins.clear();
}
bool UISkins::load(const std::string& file)
{
std::string fileContents = g_resources.loadTextFile(file);
@ -55,9 +72,9 @@ bool UISkins::load(const std::string& file)
std::string name;
it.first() >> name;
UIElementSkin *elementSkin = new UIElementSkin(name, UI::Button);
elementSkin->load(it.second());
m_elementSkins.push_back(elementSkin);
UIElementSkin *skin = new UIButtonSkin(name);
skin->load(it.second());
m_elementSkins.push_back(skin);
}
}
@ -67,11 +84,49 @@ bool UISkins::load(const std::string& file)
std::string name;
it.first() >> name;
UIElementSkin *elementSkin = new UIElementSkin(name, UI::Panel);
elementSkin->load(it.second());
m_elementSkins.push_back(elementSkin);
UIElementSkin *skin = new UIElementSkin(name, UI::Panel);
skin->load(it.second());
m_elementSkins.push_back(skin);
}
}
{
const YAML::Node& node = doc["windows"];
for(auto it = node.begin(); it != node.end(); ++it) {
std::string name;
it.first() >> name;
UIElementSkin *skin = new UIWindowSkin(name);
skin->load(it.second());
m_elementSkins.push_back(skin);
}
}
{
const YAML::Node& node = doc["labels"];
for(auto it = node.begin(); it != node.end(); ++it) {
std::string name;
it.first() >> name;
UIElementSkin *skin = new UIElementSkin(name, UI::Label);
skin->load(it.second());
m_elementSkins.push_back(skin);
}
}
{
const YAML::Node& node = doc["text edits"];
for(auto it = node.begin(); it != node.end(); ++it) {
std::string name;
it.first() >> name;
UIElementSkin *skin = new UITextEditSkin(name);
skin->load(it.second());
m_elementSkins.push_back(skin);
}
}
} catch (YAML::ParserException& e) {
logError("Malformed font file \"%s\"", file.c_str());
return false;

@ -36,6 +36,9 @@ class UISkins
public:
UISkins() { }
void init();
void terminate();
bool load(const std::string& file);
UIElementSkin *getElementSkin(UI::EElementType elementType, const std::string& name = "default");

@ -0,0 +1,45 @@
/* 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 "uitextedit.h"
#include "../fonts.h"
UITextEdit::UITextEdit(Font* font) :
UIElement(UI::TextEdit),
m_font(font)
{
if(!font)
m_font = g_fonts.get("tibia-10px-antialised");
}
void UITextEdit::render()
{
UIElement::render();
m_font->renderText(m_text, getRect(), ALIGN_LEFT, Color(0xFFBFBFBF));
}
void UITextEdit::setText(const std::string& text)
{
m_text = text;
}

@ -0,0 +1,50 @@
/* 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 UITEXTEDIT_H
#define UITEXTEDIT_H
#include "../prerequisites.h"
#include "uielement.h"
class Font;
class UITextEdit : public UIElement
{
public:
UITextEdit(Font *font = NULL);
void render();
void setText(const std::string& text);
const std::string& getText() const { return m_text; }
private:
std::string m_text;
Font *m_font;
};
typedef std::shared_ptr<UITextEdit> UITextEditPtr;
#endif // UITEXTEDIT_H

@ -0,0 +1,26 @@
/* 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 "uitexteditskin.h"

@ -0,0 +1,40 @@
/* 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 UITEXTEDITSKIN_H
#define UITEXTEDITSKIN_H
#include "../prerequisites.h"
#include "uiconstants.h"
#include "uielementskin.h"
class UITextEditSkin : public UIElementSkin
{
public:
UITextEditSkin(const std::string& name) :
UIElementSkin(name, UI::TextEdit) { }
};
#endif // UITEXTEDITSKIN_H

@ -0,0 +1,26 @@
/* 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 "uiwindow.h"

@ -0,0 +1,46 @@
/* 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 UIWINDOW_H
#define UIWINDOW_H
#include "../prerequisites.h"
#include "uicontainer.h"
class UIWindow : public UIContainer
{
public:
UIWindow(const std::string& title) :
UIContainer(UI::Window),
m_title(title) { }
const std::string& getTitle() const { return m_title; }
private:
std::string m_title;
};
typedef std::shared_ptr<UIWindow> UIWindowPtr;
#endif // UIWINDOW_H

@ -0,0 +1,60 @@
/* 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 "uiwindowskin.h"
#include "uiwindow.h"
#include "../fonts.h"
void UIWindowSkin::draw(UIElement* element)
{
UIElementSkin::draw(element);
UIWindow *window = static_cast<UIWindow*>(element);
Rect headRect = window->getRect();
Rect bodyRect = window->getRect();
headRect.setHeight(m_headHeight);
bodyRect.setTop(headRect.bottom() + 1);
m_headImage->draw(headRect);
m_titleFont->renderText(window->getTitle(),
headRect,
ALIGN_CENTER,
Color(0xFF8F8F8F));
m_bodyImage->draw(bodyRect);
}
void UIWindowSkin::load(const YAML::Node& node)
{
UIElementSkin::load(node);
node["head"]["height"] >> m_headHeight;
m_headImage = loadImage(node["head"]);
m_bodyImage = loadImage(node["body"]);
std::string fontName;
node["head"]["font"] >> fontName;
m_titleFont = g_fonts.get(fontName);
}

@ -0,0 +1,48 @@
/* 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 UIWINDOWSKIN_H
#define UIWINDOWSKIN_H
#include "../prerequisites.h"
#include "uiconstants.h"
#include "uielementskin.h"
#include "../font.h"
class UIWindowSkin : public UIElementSkin
{
public:
UIWindowSkin(const std::string& name) :
UIElementSkin(name, UI::Window) { }
void load(const YAML::Node& node);
void draw(UIElement *element);
private:
ImagePtr m_headImage;
ImagePtr m_bodyImage;
Font *m_titleFont;
int m_headHeight;
};
#endif // UIWINDOWSKIN_H

@ -351,13 +351,13 @@ bool Platform::isWindowMaximized()
return win32.maximized;
}
const char *Platform::getAppUserDir()
std::string Platform::getAppUserDir()
{
std::stringstream sdir;
sdir << PHYSFS_getUserDir() << "/." << win32.appName << "/";
if((mkdir(sdir.str().c_str()) != 0) && (errno != EEXIST))
logError("Couldn't create directory for saving configuration file. (%s)", sdir.str().c_str());
return sdir.str().c_str();
return sdir.str();
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

@ -351,7 +351,7 @@ void Platform::poll()
inputEvent.type = EV_TEXT_ENTER;
inputEvent.key.keychar = buf[0];
inputEvent.key.keycode = KC_UNKNOWN;
g_engine.onInputEvent(&inputEvent);
g_engine.onInputEvent(inputEvent);
}
}
@ -364,7 +364,7 @@ void Platform::poll()
inputEvent.key.keycode = x11.keyMap[keysym];
inputEvent.type = (event.type == KeyPress) ? EV_KEY_DOWN : EV_KEY_UP;
inputEvent.key.keychar = (len > 0) ? buf[0] : 0;
g_engine.onInputEvent(&inputEvent);
g_engine.onInputEvent(inputEvent);
}
break;
}
@ -387,14 +387,14 @@ void Platform::poll()
inputEvent.type = EV_MOUSE_WHEEL_DOWN;
break;
}
g_engine.onInputEvent(&inputEvent);
g_engine.onInputEvent(inputEvent);
break;
case MotionNotify:
inputEvent.type = EV_MOUSE_MOVE;
inputEvent.mouse.x = event.xbutton.x;
inputEvent.mouse.y = event.xbutton.y;
g_engine.onInputEvent(&inputEvent);
g_engine.onInputEvent(inputEvent);
break;
case MapNotify:
@ -826,11 +826,11 @@ bool Platform::isWindowMaximized()
return ret;
}
const char *Platform::getAppUserDir()
std::string Platform::getAppUserDir()
{
std::stringstream sdir;
sdir << PHYSFS_getUserDir() << "/." << x11.appName << "/";
if((mkdir(sdir.str().c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) && (errno != EEXIST))
logError("Couldn't create directory for saving configuration file. (%s)", sdir.str().c_str());
return sdir.str().c_str();
return sdir.str();
}

@ -52,8 +52,8 @@ void signal_handler(int sig)
void setDefaultConfigs()
{
// default size
int defWidth = 640;
int defHeight = 480;
int defWidth = 550;
int defHeight = 450;
// init on screen center
g_configs.setValue("window x", (Platform::getDisplayWidth() - defWidth)/2);
@ -101,7 +101,7 @@ int main(int argc, const char *argv[])
// create the window
Platform::createWindow(g_configs.getInteger("window x"), g_configs.getInteger("window y"),
g_configs.getInteger("window width"), g_configs.getInteger("window height"),
640, 480,
550, 450,
g_configs.getBoolean("window maximized"));
Platform::setWindowTitle("OTClient");
//Platform::setVsync();
@ -109,8 +109,7 @@ int main(int argc, const char *argv[])
// init engine
g_engine.init();
// load UI skin
g_uiSkins.load("skins/tibiaskin.yml");
g_uiSkins.init();
// state scope
{
@ -129,6 +128,8 @@ int main(int argc, const char *argv[])
// terminate stuff
g_engine.terminate();
g_uiSkins.terminate();
}
// save configurations before exiting

@ -55,14 +55,14 @@ void MenuState::onClose()
g_engine.stop();
}
void MenuState::onInputEvent(InputEvent* event)
void MenuState::onInputEvent(const InputEvent& event)
{
}
void MenuState::onResize(const Size& size)
{
recalculateMenuPanelPosition();
}
void MenuState::render()
@ -80,55 +80,123 @@ void MenuState::render()
g_graphics.drawTexturedRect(Rect(0, 0, screenSize), m_background.get(), texCoords);
}
void MenuState::update(int ticks, int elapsedTicks)
{
}
void MenuState::createMainMenu()
{
UIButtonPtr button;
int y = 16;
int y = 0;
m_menuPanel = UIPanelPtr(new UIPanel);
m_menuPanel->setSkin("roundedGridPanel");
recalculateMenuPanelPosition();
button = UIButtonPtr(new UIButton("Enter Game"));
button->setRect(Rect(16, y, 86, 20));
m_menuPanel->addChild(button);
y += 30;
m_menuPanel->anchorLeft(g_ui->left());
m_menuPanel->anchorBottom(g_ui->bottom());
m_menuPanel->setSize(Size(118, 172));
m_menuPanel->setMargin(0, 60, 70, 0);
g_ui->addChild(m_menuPanel);
button = UIButtonPtr(new UIButton("Access Account"));
button->setRect(Rect(16, y, 86, 20));
// main menu
UIButtonPtr enterGameButton = UIButtonPtr(new UIButton("Enter Game"));
enterGameButton->anchorTop(m_menuPanel->top());
enterGameButton->anchorHorizontalCenter(m_menuPanel->horizontalCenter());
enterGameButton->setMargin(y += 16);
m_menuPanel->addChild(enterGameButton);
UIButtonPtr button = UIButtonPtr(new UIButton("Access Account"));
button->anchorTop(m_menuPanel->top());
button->anchorHorizontalCenter(m_menuPanel->horizontalCenter());
button->setMargin(y += 30);
m_menuPanel->addChild(button);
y += 30;
button = UIButtonPtr(new UIButton("Options"));
button->setRect(Rect(16, y, 86, 20));
button->anchorTop(m_menuPanel->top());
button->anchorHorizontalCenter(m_menuPanel->horizontalCenter());
button->setMargin(y += 30);
m_menuPanel->addChild(button);
y += 30;
button = UIButtonPtr(new UIButton("Info"));
button->setRect(Rect(16, y, 86, 20));
button->anchorTop(m_menuPanel->top());
button->anchorHorizontalCenter(m_menuPanel->horizontalCenter());
button->setMargin(y += 30);
m_menuPanel->addChild(button);
y += 30;
button = UIButtonPtr(new UIButton("Exit Game"));
button->setRect(Rect(16, y, 86, 20));
button->anchorLeft(m_menuPanel->left());
button->anchorTop(m_menuPanel->top());
button->anchorHorizontalCenter(m_menuPanel->horizontalCenter());
button->setMargin(y += 30);
button->onClick([]{ g_engine.stop(); });
m_menuPanel->addChild(button);
y += 30;
g_ui->addChild(m_menuPanel);
// login window
UIWindowPtr window(new UIWindow("Enter Game"));
UIElementWeakPtr weakWindow(window);
window->setSize(Size(236, 178));
window->anchorHorizontalCenter(g_ui->horizontalCenter());
window->anchorVerticalCenter(g_ui->verticalCenter());
window->setVisible(false);
g_ui->addChild(window);
UILabelPtr label(new UILabel("Account name:"));
label->anchorLeft(window->left());
label->anchorTop(window->top());
label->setMargin(18, 33);
window->addChild(label);
label = UILabelPtr(new UILabel("Password:"));
label->anchorLeft(window->left());
label->anchorTop(window->top());
label->setMargin(18, 62);
window->addChild(label);
label = UILabelPtr(new UILabel("If you don't have\nan account yet:"));
label->anchorLeft(window->left());
label->anchorTop(window->top());
label->setMargin(18, 87);
window->addChild(label);
button = UIButtonPtr(new UIButton("Create Account"));
button->anchorLeft(window->left());
button->anchorTop(window->top());
button->setMargin(132, 94);
window->addChild(button);
button = UIButtonPtr(new UIButton("Ok"));
button->setSize(Size(43, 20));
button->anchorRight(window->right());
button->anchorBottom(window->bottom());
button->setMargin(0, 0, 10, 66);
button->onClick([weakWindow]{
UIElementPtr window = weakWindow.lock();
if(window)
window->setVisible(false);
});
window->addChild(button);
button = UIButtonPtr(new UIButton("Cancel"));
button->setSize(Size(43, 20));
button->anchorRight(window->right());
button->anchorBottom(window->bottom());
button->setMargin(0, 0, 10, 13);
button->onClick([weakWindow]{
UIElementPtr window = weakWindow.lock();
if(window)
window->setVisible(false);
});
window->addChild(button);
UITextEditPtr textEdit(new UITextEdit);
textEdit->anchorRight(window->right());
textEdit->anchorTop(window->top());
textEdit->setMargin(32, 0, 0, 18);
window->addChild(textEdit);
textEdit = UITextEditPtr(new UITextEdit);
textEdit->anchorRight(window->right());
textEdit->anchorTop(window->top());
textEdit->setMargin(61, 0, 0, 18);
window->addChild(textEdit);
enterGameButton->onClick([weakWindow]{
UIElementPtr window = weakWindow.lock();
if(window)
window->setVisible(true);
});
}
void MenuState::recalculateMenuPanelPosition()
{
if(m_menuPanel) {
// calculate panel rect
Size panelSize = Size(117, 171);
Rect panelRect = Rect(0, 0, panelSize);
panelRect.moveBottomLeft(Point(60, g_graphics.getScreenSize().height() - 70));
m_menuPanel->setRect(panelRect);
}
}

@ -40,15 +40,13 @@ public:
void onLeave();
void onClose();
void onInputEvent(InputEvent *event);
void onInputEvent(const InputEvent& event);
void onResize(const Size& size);
void render();
void update(int ticks, int elapsedTicks);
private:
void createMainMenu();
void recalculateMenuPanelPosition();
UIPanelPtr m_menuPanel;
TexturePtr m_background;

@ -48,7 +48,7 @@ void TestState::onClose()
g_engine.stop();
}
void TestState::onInputEvent(InputEvent* event)
void TestState::onInputEvent(const InputEvent& event)
{
}

@ -37,7 +37,7 @@ public:
void onLeave();
void onClose();
void onInputEvent(InputEvent *event);
void onInputEvent(const InputEvent& event);
void onResize(const Size& size);
virtual void render();

Loading…
Cancel
Save