remove game state classes

scripting improvements
This commit is contained in:
Eduardo Bart 2011-04-22 10:49:46 -03:00
parent a3901b0251
commit e611734396
32 changed files with 428 additions and 435 deletions

View File

@ -55,8 +55,6 @@ ENDIF(CMAKE_BUILD_TYPE STREQUAL "Debug")
SET(SOURCES SET(SOURCES
# game sources # game sources
src/main.cpp src/main.cpp
src/menustate.cpp
src/teststate.cpp
# game net # game net
src/protocollogin.cpp src/protocollogin.cpp
@ -66,6 +64,7 @@ SET(SOURCES
src/framework/core/configs.cpp src/framework/core/configs.cpp
src/framework/core/resources.cpp src/framework/core/resources.cpp
src/framework/core/engine.cpp src/framework/core/engine.cpp
src/framework/core/modules.cpp
# framework script # framework script
src/framework/script/luascript.cpp src/framework/script/luascript.cpp

View File

@ -50,8 +50,8 @@ window#enterGameWindow:
margin.bottom: 10 margin.bottom: 10
margin.right: 13 margin.right: 13
onClick: | onClick: |
enterGameWindow:destroy() self:getParent():destroy()
enterGameWindow = nil self:getParent():getParent():unlock()
textEdit#accountNameTextEdit: textEdit#accountNameTextEdit:
anchors.right: parent.right anchors.right: parent.right

View File

@ -57,4 +57,6 @@ window#infoWindow:
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
margin.top: 191 margin.top: 191
margin.left: 188 margin.left: 188
onClick: |
self:getParent():destroy()

View File

@ -1,6 +1,15 @@
-- events -- main menu methods
function MainMenu_create()
mainMenu = loadUI("modules/mainmenu/mainmenu.yml")
end
function MainMenu_destroy()
mainMenu:destroy()
end
function MainMenu_enterGameClicked() function MainMenu_enterGameClicked()
enterGameWindow = loadUI("modules/mainmenu/entergamewindow.yml") enterGameWindow = loadUI("modules/mainmenu/entergamewindow.yml")
enterGameWindow:getParent():lock(enterGameWindow)
end end
function MainMenu_optionsClicked() function MainMenu_optionsClicked()
@ -12,12 +21,5 @@ function MainMenu_infoClicked()
end end
function MainMenu_exitClicked() function MainMenu_exitClicked()
exitGame() onApplicationClose()
end end
-- create main menu
function MainMenu_create()
menuPanel = loadUI("modules/mainmenu/mainmenu.yml")
end
MainMenu_create()

View File

@ -1,41 +1,51 @@
panel#mainMenu: panel#background:
skin: roundedGridPanel skin:
size: [117, 171] image: background.png
antialised: true
size: [500, 500]
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
margin.left: 60
margin.bottom: 70
button#enterGameButton: panel#mainMenu:
text: Enter Game skin: roundedGridPanel
anchors.top: parent.top size: [117, 171]
anchors.horizontalCenter: parent.horizontalCenter anchors.left: parent.left
margin.top: 16 anchors.bottom: parent.bottom
onClick: MainMenu_enterGameClicked() margin.left: 60
margin.bottom: 70
button#enterGameButton:
text: Enter Game
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin.top: 16
onClick: MainMenu_enterGameClicked()
button#accessAccountButton: button#accessAccountButton:
text: Access Account text: Access Account
anchors.top: parent.top anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
margin.top: 46 margin.top: 46
button#optionsButton: button#optionsButton:
text: Options text: Options
anchors.top: parent.top anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
margin.top: 76 margin.top: 76
onClick: MainMenu_optionsClicked() onClick: MainMenu_optionsClicked()
button#infoButton: button#infoButton:
text: Info text: Info
anchors.top: parent.top anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
margin.top: 106 margin.top: 106
onClick: MainMenu_infoClicked() onClick: MainMenu_infoClicked()
button#exitGameButton: button#exitGameButton:
text: Exit text: Exit
anchors.top: parent.top anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
margin.top: 136 margin.top: 136
onClick: MainMenu_exitClicked() onClick: MainMenu_exitClicked()

View File

@ -0,0 +1,20 @@
-- menu state
function onEnterMenuState()
MainMenu_create()
end
function onLeaveMenuState()
MainMenu_destroy()
end
function onApplicationClose()
onLeaveMenuState()
exitGame()
end
-- here is where everything starts
if not initialStateLoaded then
onEnterMenuState()
setOnApplicationClose(onApplicationClose)
initialStateLoaded = true
end

View File

@ -0,0 +1,10 @@
title: Main menu
notes: Used to create the main menu
enabled: true
#dependencies
interface: 020
author: edubart
version: 0.2
scripts:
- menustate.lua
- mainmenu.lua

View File

@ -110,5 +110,4 @@ window#optionsWindow:
margin.right: 10 margin.right: 10
margin.bottom: 13 margin.bottom: 13
onClick: | onClick: |
optionsWindow:destroy() self:getParent():destroy()
optionsWindow = nil

View File

@ -42,14 +42,23 @@ void Engine::init()
void Engine::terminate() void Engine::terminate()
{ {
// force last state exit
changeState(NULL);
// terminate stuff // terminate stuff
g_fonts.terminate(); g_fonts.terminate();
g_graphics.terminate(); g_graphics.terminate();
} }
void Engine::poll()
{
// poll platform events
Platform::poll();
// poll network events
Connection::poll();
// poll diaptcher tasks
g_dispatcher.poll();
}
void Engine::run() void Engine::run()
{ {
std::string fpsText; std::string fpsText;
@ -65,14 +74,7 @@ void Engine::run()
while(!m_stopping) { while(!m_stopping) {
m_lastFrameTicks = Platform::getTicks(); m_lastFrameTicks = Platform::getTicks();
// poll platform events poll();
Platform::poll();
// poll network events
Connection::poll();
// poll diaptcher tasks
g_dispatcher.poll();
// render only when visible // render only when visible
if(Platform::isWindowVisible()) { if(Platform::isWindowVisible()) {
@ -93,8 +95,6 @@ void Engine::run()
// render // render
g_graphics.beginRender(); g_graphics.beginRender();
if(m_currentState)
m_currentState->render();
UIContainer::getRootContainer()->render(); UIContainer::getRootContainer()->render();
// render fps // render fps
@ -117,39 +117,19 @@ void Engine::stop()
m_stopping = true; m_stopping = true;
} }
void Engine::changeState(GameState* newState)
{
if(m_currentState)
m_currentState->onLeave();
m_currentState = newState;
if(m_currentState)
m_currentState->onEnter();
}
void Engine::onClose() void Engine::onClose()
{ {
if(m_currentState) if(m_onCloseCallback)
m_currentState->onClose(); g_dispatcher.addTask(m_onCloseCallback);
} }
void Engine::onResize(const Size& size) void Engine::onResize(const Size& size)
{ {
g_graphics.resize(size); g_graphics.resize(size);
UIContainer::getRootContainer()->setSize(size); UIContainer::getRootContainer()->setSize(size);
if(m_currentState)
m_currentState->onResize(size);
} }
void Engine::onInputEvent(const InputEvent& event) void Engine::onInputEvent(const InputEvent& event)
{ {
bool eventCaptured = false; UIContainer::getRootContainer()->onInputEvent(event);
// events goes to the state first
if(m_currentState)
eventCaptured = m_currentState->onInputEvent(event);
// if the state didn't capture the input then goes to the gui
if(!eventCaptured)
UIContainer::getRootContainer()->onInputEvent(event);
} }

View File

@ -26,19 +26,20 @@
#define ENGINE_H #define ENGINE_H
#include <prerequisites.h> #include <prerequisites.h>
#include <core/gamestate.h> #include <core/input.h>
class Engine class Engine
{ {
public: public:
Engine() : m_stopping(false), Engine() : m_stopping(false),
m_running(false), m_running(false),
m_calculateFps(false), m_calculateFps(false) { }
m_currentState(NULL) { }
void init(); void init();
void terminate(); void terminate();
/// Poll events
void poll();
/// Main loop /// Main loop
void run(); void run();
@ -46,8 +47,6 @@ public:
void stop(); void stop();
/// Change current game state /// Change current game state
void changeState(GameState *newState);
bool isRunning() const { return m_running; } bool isRunning() const { return m_running; }
bool isStopping() const { return m_stopping; } bool isStopping() const { return m_stopping; }
@ -64,13 +63,16 @@ public:
/// Return the current ticks on this frame /// Return the current ticks on this frame
int getCurrentFrameTicks() const { return m_lastFrameTicks; } int getCurrentFrameTicks() const { return m_lastFrameTicks; }
void setOnClose(Callback onCloseCallback) { m_onCloseCallback = onCloseCallback; }
private: private:
bool m_stopping; bool m_stopping;
bool m_running; bool m_running;
bool m_calculateFps; bool m_calculateFps;
GameState *m_currentState;
int m_lastFrameTicks; int m_lastFrameTicks;
Callback m_onCloseCallback;
}; };
extern Engine g_engine; extern Engine g_engine;

View File

@ -1,55 +0,0 @@
/* 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 GAMESTATE_H
#define GAMESTATE_H
#include <prerequisites.h>
#include <core/input.h>
struct InputEvent;
class GameState
{
public:
GameState() { }
virtual ~GameState() { }
/// Fired when enter the state
virtual void onEnter() = 0;
/// Fired when leaves the state
virtual void onLeave() = 0;
/// Fired when user tries to close the window
virtual void onClose() = 0;
/// Fired for every user input event, this is called before processing UI input and if it returns false the input is not passed to the UI
virtual bool onInputEvent(const InputEvent& event) = 0;
/// Fired when main window is resized
virtual void onResize(const Size& size) = 0;
/// Fired before redering the UI
virtual void render() = 0;
};
#endif // GAMESTATE_H

View File

@ -22,26 +22,5 @@
*/ */
#ifndef TESTSTATE_H #include "modules.h"
#define TESTSTATE_H
#include <prerequisites.h>
#include <core/gamestate.h>
class TestState : public GameState
{
public:
TestState() { }
void onEnter();
void onLeave();
void onClose();
bool onInputEvent(const InputEvent& event);
void onResize(const Size& size);
virtual void render();
virtual void update(int ticks, int elapsedTicks);
};
#endif // TESTSTATE_H

View File

@ -22,41 +22,11 @@
*/ */
#include <core/engine.h> #ifndef MODULES_H
#include <graphics/graphics.h> #define MODULES_H
#include "teststate.h"
void TestState::onEnter() class Modules
{ {
};
} #endif // MODULES_H
void TestState::onLeave()
{
}
void TestState::onClose()
{
g_engine.stop();
}
bool TestState::onInputEvent(const InputEvent& event)
{
return false;
}
void TestState::onResize(const Size& size)
{
}
void TestState::render()
{
}
void TestState::update(int ticks, int elapsedTicks)
{
}

View File

@ -27,9 +27,16 @@
#include <graphics/graphics.h> #include <graphics/graphics.h>
#include <graphics/textures.h> #include <graphics/textures.h>
Image::Image(TexturePtr texture)
: m_texture(texture)
{
m_textureCoords = Rect(0, 0, m_texture->getSize());
}
Image::Image(const std::string& texture) Image::Image(const std::string& texture)
{ {
m_texture = g_textures.get(texture); m_texture = g_textures.get(texture);
m_textureCoords = Rect(0, 0, m_texture->getSize());
} }
Image::Image(const std::string& texture, Rect textureCoords) : Image::Image(const std::string& texture, Rect textureCoords) :

View File

@ -31,7 +31,7 @@
class Image class Image
{ {
public: public:
Image(TexturePtr texture) : m_texture(texture) { } Image(TexturePtr texture);
Image(TexturePtr texture, Rect textureCoords) : m_texture(texture), m_textureCoords(textureCoords) { } Image(TexturePtr texture, Rect textureCoords) : m_texture(texture), m_textureCoords(textureCoords) { }
Image(const std::string& texture); Image(const std::string& texture);
Image(const std::string& texture, Rect textureCoords); Image(const std::string& texture, Rect textureCoords);

View File

@ -33,6 +33,7 @@ void LuaScript::registerFunctions()
registerGlobalFunction("exitGame", &LuaScript::lua_exitGame); registerGlobalFunction("exitGame", &LuaScript::lua_exitGame);
registerGlobalFunction("loadUI", &LuaScript::lua_loadUI); registerGlobalFunction("loadUI", &LuaScript::lua_loadUI);
registerGlobalFunction("getUIRootContainer", &LuaScript::lua_getUIRootContainer); registerGlobalFunction("getUIRootContainer", &LuaScript::lua_getUIRootContainer);
registerGlobalFunction("setOnApplicationClose", &LuaScript::lua_setOnApplicationClose);
registerClass("UILayout"); registerClass("UILayout");
registerClass("UIElement", "UILayout"); registerClass("UIElement", "UILayout");
@ -42,8 +43,11 @@ void LuaScript::registerFunctions()
registerClass("UIContainer", "UIElement"); registerClass("UIContainer", "UIElement");
registerClass("UIWindow", "UIContainer"); registerClass("UIWindow", "UIContainer");
registerMemberFunction("UIElement", "getParent", &LuaScript::lua_UIElement_getParent);
registerMemberFunction("UIElement", "destroy", &LuaScript::lua_UIElement_destroy); registerMemberFunction("UIElement", "destroy", &LuaScript::lua_UIElement_destroy);
registerMemberFunction("UIContainer", "getChildByID", &LuaScript::lua_UIContainer_getChildByID); registerMemberFunction("UIContainer", "getChildByID", &LuaScript::lua_UIContainer_getChildByID);
registerMemberFunction("UIContainer", "lock", &LuaScript::lua_UIContainer_lock);
registerMemberFunction("UIContainer", "unlock", &LuaScript::lua_UIContainer_unlock);
registerMemberFunction("UIButton", "setOnClick", &LuaScript::lua_UIButton_setOnClick); registerMemberFunction("UIButton", "setOnClick", &LuaScript::lua_UIButton_setOnClick);
} }
@ -74,10 +78,34 @@ int LuaScript::lua_getUIRootContainer()
return 1; return 1;
} }
int LuaScript::lua_setOnApplicationClose()
{
int funcRef = popFunction();
g_engine.setOnClose([this, funcRef] {
pushFunction(funcRef);
callFunction();
});
return 1;
}
int LuaScript::lua_UIElement_destroy() int LuaScript::lua_UIElement_destroy()
{ {
UIElementPtr element = boost::static_pointer_cast<UIElement>(popClassInstance()); UIElementPtr element = boost::static_pointer_cast<UIElement>(popClassInstance());
element->destroy(); if(element)
element->destroy();
else
pushNil();
return 1;
}
int LuaScript::lua_UIElement_getParent()
{
UIElementPtr element = boost::static_pointer_cast<UIElement>(popClassInstance());
if(element)
pushClassInstance(element->getParent());
else
pushNil();
return 1; return 1;
} }
@ -87,8 +115,9 @@ int LuaScript::lua_UIButton_setOnClick()
UIButtonPtr button = boost::static_pointer_cast<UIButton>(popClassInstance()); UIButtonPtr button = boost::static_pointer_cast<UIButton>(popClassInstance());
if(button) { if(button) {
int funcRef = popFunction(); int funcRef = popFunction();
button->setOnClick([this, funcRef] { button->setOnClick([this, funcRef](UIButtonPtr button) {
pushFunction(funcRef); pushFunction(funcRef);
setSelf(button);
callFunction(); callFunction();
}); });
} else { } else {
@ -100,13 +129,29 @@ int LuaScript::lua_UIButton_setOnClick()
int LuaScript::lua_UIContainer_getChildByID() int LuaScript::lua_UIContainer_getChildByID()
{ {
std::string id = popString(); std::string id = popString();
ScriptablePtr object = popClassInstance(); UIContainerPtr container = boost::static_pointer_cast<UIContainer>(popClassInstance());
if(object && strcmp("UIContainer", object->getScriptableName()) == 0) { if(container)
UIContainerPtr container = boost::static_pointer_cast<UIContainer>(object);
pushClassInstance(container->getChildById(id)); pushClassInstance(container->getChildById(id));
} else { else
pushNil(); pushNil();
}
return 1; return 1;
} }
int LuaScript::lua_UIContainer_lock()
{
UIElementPtr element = boost::static_pointer_cast<UIElement>(popClassInstance());
UIContainerPtr container = boost::static_pointer_cast<UIContainer>(popClassInstance());
if(container && element) {
container->lockElement(element);
}
return 1;
}
int LuaScript::lua_UIContainer_unlock()
{
UIContainerPtr container = boost::static_pointer_cast<UIContainer>(popClassInstance());
if(container) {
container->unlockElement();
}
return 1;
}

View File

@ -49,10 +49,22 @@ LuaScript::~LuaScript()
lua_close(L); lua_close(L);
} }
void LuaScript::loadAllModules()
{
std::list<std::string> modules = g_resources.getDirectoryFiles("modules");
foreach(const std::string& module, modules) {
std::list<std::string> moduleFiles = g_resources.getDirectoryFiles(std::string("modules/") + module);
foreach(const std::string& moduleFile, moduleFiles) {
if(boost::ends_with(moduleFile, ".lua"))
loadFile(std::string("modules/") + module + "/" + moduleFile);
}
}
}
bool LuaScript::loadFile(const std::string& fileName) bool LuaScript::loadFile(const std::string& fileName)
{ {
if(!g_resources.fileExists(fileName)) { if(!g_resources.fileExists(fileName)) {
logError("lua script file '%s' doesn't exist", fileName.c_str()); logError("script file '%s' doesn't exist", fileName.c_str());
return false; return false;
} }
std::string fileContents = g_resources.loadTextFile(fileName); std::string fileContents = g_resources.loadTextFile(fileName);
@ -64,20 +76,19 @@ bool LuaScript::loadBuffer(const std::string& text, const std::string& what)
// load buffer // load buffer
int ret = luaL_loadbuffer(L, text.c_str(), text.length(), what.c_str()); int ret = luaL_loadbuffer(L, text.c_str(), text.length(), what.c_str());
if(ret != 0){ if(ret != 0){
logError((std::string("while parsing lua code: ") + popString()).c_str()); reportError(popString());
return false; return false;
} }
// check if that is loaded as a function // check if is loaded as a function
if(lua_isfunction(L, -1) == 0) { if(lua_isfunction(L, -1) == 0) {
logError("lua code not loaded as function");
return false; return false;
} }
// execute it // execute it
ret = lua_pcall(L, 0, 0, 0); ret = lua_pcall(L, 0, 0, 0);
if(ret != 0){ if(ret != 0){
logError((std::string("while loading lua code: ") + popString()).c_str()); reportError(popString());
return false; return false;
} }
@ -86,21 +97,30 @@ bool LuaScript::loadBuffer(const std::string& text, const std::string& what)
int LuaScript::loadBufferAsFunction(const std::string& text, const std::string& what) int LuaScript::loadBufferAsFunction(const std::string& text, const std::string& what)
{ {
int ret = luaL_loadstring(L, text.c_str()); int ret = luaL_loadbuffer(L, text.c_str(), text.length(), what.c_str());
if(ret != 0){ if(ret != 0){
logError((std::string("while parsing lua code: ") + popString()).c_str()); reportError(popString());
return LUA_REFNIL; return LUA_REFNIL;
} }
// check if that is loaded as a function // check if is loaded as a function
if(lua_isfunction(L, -1) == 0) { if(lua_isfunction(L, -1) == 0) {
logError("lua code not loaded as function");
return LUA_REFNIL; return LUA_REFNIL;
} }
return popFunction(); return popFunction();
} }
void LuaScript::reportError(const std::string& errorDesc, const char *funcName)
{
std::stringstream ss;
ss << "LUA script error";
if(funcName)
ss << " in " << funcName << "()";
ss << ": " << errorDesc << std::endl;
logError(ss.str().c_str());
}
int LuaScript::getStackSize() int LuaScript::getStackSize()
{ {
return lua_gettop(L); return lua_gettop(L);
@ -120,23 +140,15 @@ bool LuaScript::popBoolean()
int32_t LuaScript::popInteger() int32_t LuaScript::popInteger()
{ {
double d; double d = lua_tonumber(L, -1);
if(lua_istable(L, -1)) { pop(1);
lua_getfield(L, -1, "__intValue");
d = lua_tonumber(L, -1);
pop(2);
}
else{
d = lua_tonumber(L, -1);
pop(1);
}
return (int)d; return (int)d;
} }
std::string LuaScript::popString() std::string LuaScript::popString()
{ {
size_t len; size_t len;
const char* cstr = lua_tolstring(L, -1, &len); const char *cstr = lua_tolstring(L, -1, &len);
std::string str(cstr, len); std::string str(cstr, len);
pop(); pop();
return str; return str;
@ -169,29 +181,30 @@ void LuaScript::pushUserdata(void* ptr)
void LuaScript::pushClassInstance(const ScriptablePtr& object) void LuaScript::pushClassInstance(const ScriptablePtr& object)
{ {
if(object->getScriptableName()) { if(object && object->getScriptableName()) {
new(lua_newuserdata(L, sizeof(ScriptableWeakPtr))) ScriptableWeakPtr(object); new(lua_newuserdata(L, sizeof(ScriptableWeakPtr))) ScriptableWeakPtr(object);
lua_getfield(L, LUA_REGISTRYINDEX, (std::string(object->getScriptableName()) + "_mt").c_str()); lua_getfield(L, LUA_REGISTRYINDEX, (std::string(object->getScriptableName()) + "_mt").c_str());
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
} else {
lua_pushnil(L);
} }
} }
ScriptablePtr LuaScript::popClassInstance() ScriptablePtr LuaScript::popClassInstance()
{ {
if(!lua_isuserdata(L, -1)) { if(!lua_isuserdata(L, -1)) {
logError("Couldn't pop a class instance, top objet is not a valid type (%s)", luaL_typename(L, -1)); reportError(format("couldn't pop a class instance, top objet is not a valid type (%s)", luaL_typename(L, -1)));
lua_pop(L, 1); lua_pop(L, 1);
return ScriptablePtr(); return ScriptablePtr();
} }
ScriptableWeakPtr *objectRef = (ScriptableWeakPtr *)lua_touserdata(L, -1); ScriptableWeakPtr *objectRef = (ScriptableWeakPtr *)lua_touserdata(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
return objectRef->lock();
}
int LuaScript::popFunction() ScriptablePtr object = objectRef->lock();
{ if(!object)
return luaL_ref(L, LUA_REGISTRYINDEX); reportError(format("attempt to retrive class instance from a object that is already expired"));
return object;
} }
void LuaScript::pushFunction(int functionRef) void LuaScript::pushFunction(int functionRef)
@ -199,9 +212,40 @@ void LuaScript::pushFunction(int functionRef)
lua_rawgeti(L, LUA_REGISTRYINDEX, functionRef); lua_rawgeti(L, LUA_REGISTRYINDEX, functionRef);
} }
void LuaScript::callFunction(int numArgs, bool itReturnsValue) int LuaScript::popFunction()
{ {
lua_call(L, numArgs, itReturnsValue ? 1 : 0); return luaL_ref(L, LUA_REGISTRYINDEX);
}
void LuaScript::releaseFunction(int functionRef)
{
luaL_unref(L, LUA_REGISTRYINDEX, functionRef);
}
void LuaScript::callFunction(int numArgs)
{
int size = lua_gettop(L);
int errorIndex = size - numArgs;
lua_pushcfunction(L, &LuaScript::luaErrorHandler);
lua_insert(L, errorIndex);
int ret = lua_pcall(L, numArgs, 0, errorIndex);
if(ret != 0) {
reportError(popString());
}
lua_remove(L, errorIndex);
if(lua_gettop(L) + numArgs + 1 != size)
reportError("stack size changed!");
}
void LuaScript::setSelf(const ScriptablePtr& scriptable, int envIndex)
{
lua_getfenv(L, envIndex);
pushClassInstance(scriptable);
lua_setfield(L, -2, "self");
lua_pop(L, 1);
} }
void LuaScript::setupPackageLoader() void LuaScript::setupPackageLoader()
@ -342,3 +386,20 @@ int LuaScript::luaFunctionCallback(lua_State* L)
return (g_lua.*(g_lua.m_functions[id]))(); return (g_lua.*(g_lua.m_functions[id]))();
} }
int LuaScript::luaErrorHandler(lua_State *L)
{
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
if(!lua_istable(L, -1)) {
lua_pop(L, 1);
return 1;
}
lua_getfield(L, -1, "traceback");
if(!lua_isfunction(L, -1)) {
lua_pop(L, 2);
return 1;
}
lua_pushvalue(L, 1);
lua_pushinteger(L, 2);
lua_call(L, 2, 1);
return 1;
}

View File

@ -29,15 +29,19 @@
#include <script/scriptable.h> #include <script/scriptable.h>
#include <lua.hpp> #include <lua.hpp>
#define reportFuncError(a) reportError(a, __FUNCTION__)
class LuaScript class LuaScript
{ {
public: public:
LuaScript(); LuaScript();
virtual ~LuaScript(); virtual ~LuaScript();
void loadAllModules();
bool loadFile(const std::string& fileName); bool loadFile(const std::string& fileName);
bool loadBuffer(const std::string& text, const std::string& what = "luaBuffer"); bool loadBuffer(const std::string& text, const std::string& what = "luaBuffer");
int loadBufferAsFunction(const std::string& text, const std::string& what = "luaBuffer"); int loadBufferAsFunction(const std::string& text, const std::string& what = "luaBuffer");
void reportError(const std::string& errorDesc, const char *funcName = NULL);
int getStackSize(); int getStackSize();
@ -52,9 +56,12 @@ public:
int32_t popInteger(); int32_t popInteger();
std::string popString(); std::string popString();
int popFunction();
void pushFunction(int functionRef); void pushFunction(int functionRef);
void callFunction(int numArgs = 0, bool itReturnsValue = false); int popFunction();
void releaseFunction(int functionRef);
void callFunction(int numArgs = 0);
void setSelf(const ScriptablePtr& scriptable, int envIndex = -1);
void pushClassInstance(const ScriptablePtr& object); void pushClassInstance(const ScriptablePtr& object);
ScriptablePtr popClassInstance(); ScriptablePtr popClassInstance();
@ -70,20 +77,25 @@ public:
static int luaPackageLoader(lua_State* L); static int luaPackageLoader(lua_State* L);
static int luaCollectClassInstance(lua_State* L); static int luaCollectClassInstance(lua_State* L);
static int luaCompareClassInstances(lua_State* L); static int luaCompareClassInstances(lua_State* L);
static int luaErrorHandler(lua_State *L);
void registerFunctions(); void registerFunctions();
int lua_UIButton_setOnClick(); int lua_UIButton_setOnClick();
int lua_UIElement_getParent();
int lua_UIElement_destroy(); int lua_UIElement_destroy();
// container functions // container functions
int lua_UIContainer_getChildByID(); int lua_UIContainer_getChildByID();
int lua_UIContainer_lock();
int lua_UIContainer_unlock();
// global functions // global functions
int lua_exitGame(); int lua_exitGame();
int lua_loadUI(); int lua_loadUI();
int lua_getUIRootContainer(); int lua_getUIRootContainer();
int lua_setOnApplicationClose();
private: private:
std::vector<LuaCFunction> m_functions; std::vector<LuaCFunction> m_functions;

View File

@ -33,8 +33,8 @@ void UIButton::onInputEvent(const InputEvent& event)
} else if(event.type == EV_MOUSE_LUP && m_state == UI::ButtonDown) { } else if(event.type == EV_MOUSE_LUP && m_state == UI::ButtonDown) {
m_state = UI::ButtonUp; m_state = UI::ButtonUp;
if(getRect().contains(event.mousePos)) { if(getRect().contains(event.mousePos)) {
if(m_buttonClickCallback) { if(m_onClickCallback) {
g_dispatcher.addTask(m_buttonClickCallback); g_dispatcher.addTask(boost::bind(m_onClickCallback, boost::static_pointer_cast<UIButton>(shared_from_this())));
} }
} }
} }

View File

@ -29,8 +29,13 @@
#include <ui/uielement.h> #include <ui/uielement.h>
#include <graphics/borderedimage.h> #include <graphics/borderedimage.h>
class UIButton;
typedef boost::shared_ptr<UIButton> UIButtonPtr;
class UIButton : public UIElement class UIButton : public UIElement
{ {
typedef boost::function<void(UIButtonPtr)> OnClick;
public: public:
UIButton() : UIButton() :
UIElement(UI::Button), UIElement(UI::Button),
@ -43,16 +48,14 @@ public:
UI::EButtonState getState() { return m_state; } UI::EButtonState getState() { return m_state; }
void setOnClick(const Callback& callback) { m_buttonClickCallback = callback; } void setOnClick(const OnClick& callback) { m_onClickCallback = callback; }
virtual const char *getScriptableName() const { return "UIButton"; } virtual const char *getScriptableName() const { return "UIButton"; }
private: private:
std::string m_text; std::string m_text;
UI::EButtonState m_state; UI::EButtonState m_state;
Callback m_buttonClickCallback; OnClick m_onClickCallback;
}; };
typedef boost::shared_ptr<UIButton> UIButtonPtr;
#endif // UIBUTTON_H #endif // UIBUTTON_H

View File

@ -25,6 +25,7 @@
#include <prerequisites.h> #include <prerequisites.h>
#include <core/resources.h> #include <core/resources.h>
#include <ui/uicontainer.h> #include <ui/uicontainer.h>
#include <core/dispatcher.h>
UIContainerPtr rootContainer(new UIContainer); UIContainerPtr rootContainer(new UIContainer);
@ -71,6 +72,15 @@ UIElementPtr UIContainer::getChildById(const std::string& id)
return UIElementPtr(); return UIElementPtr();
} }
UIElementPtr UIContainer::getChildByPos(const Point& pos)
{
for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
if((*it)->getRect().contains(pos))
return (*it);
}
return UIElementPtr();
}
UIElementPtr UIContainer::recursiveGetChildById(const std::string& id) UIElementPtr UIContainer::recursiveGetChildById(const std::string& id)
{ {
if(getId() == id) if(getId() == id)
@ -93,6 +103,21 @@ UIElementPtr UIContainer::recursiveGetChildById(const std::string& id)
return UIElementPtr(); return UIElementPtr();
} }
void UIContainer::pushChildToTop(const UIElementPtr& child)
{
bool removed = false;
for(auto it = m_children.begin(); it != m_children.end(); ++it) {
if((*it) == child) {
removed = true;
m_children.erase(it);
break;
}
}
if(removed) {
m_children.push_back(child);
}
}
void UIContainer::render() void UIContainer::render()
{ {
UIElement::render(); UIElement::render();
@ -119,9 +144,10 @@ void UIContainer::onInputEvent(const InputEvent& event)
} }
// mouse events // mouse events
} else if(event.type & EV_MOUSE) { } else if(event.type & EV_MOUSE) {
// mouse down and wheel events only go to elements that contains the mouse position and are not containers // mouse down and wheel events only go to elements that contains the mouse position
if((event.type & EV_DOWN || event.type & EV_MOUSE_WHEEL) && !child->asUIContainer()) { if(event.type & EV_DOWN || event.type & EV_MOUSE_WHEEL) {
if(child->getRect().contains(event.mousePos)) { // the child must contains the mouse position and be on top
if(child->getRect().contains(event.mousePos) && child == getChildByPos(event.mousePos)) {
// focus it // focus it
if(event.type == EV_MOUSE_LDOWN && child->isFocusable()) if(event.type == EV_MOUSE_LDOWN && child->isFocusable())
setFocusedElement(child); setFocusedElement(child);
@ -171,9 +197,17 @@ void UIContainer::setFocusedElement(UIElementPtr focusedElement)
m_focusedElement->setFocused(false); m_focusedElement->setFocused(false);
m_focusedElement->onFocusChange(); m_focusedElement->onFocusChange();
} }
m_focusedElement = focusedElement; m_focusedElement = focusedElement;
m_focusedElement->setFocused(true); if(m_focusedElement) {
m_focusedElement->onFocusChange(); m_focusedElement->setFocused(true);
m_focusedElement->onFocusChange();
}
}
// when containers are focused they go to the top
if(focusedElement && focusedElement->asUIContainer()) {
g_dispatcher.addTask(boost::bind(&UIContainer::pushChildToTop, asUIContainer(), m_focusedElement));
} }
} }

View File

@ -44,8 +44,14 @@ public:
void removeChild(UIElementPtr child); void removeChild(UIElementPtr child);
/// Find an element in this container by id /// Find an element in this container by id
UIElementPtr getChildById(const std::string& id); UIElementPtr getChildById(const std::string& id);
/// Find an element by position
UIElementPtr getChildByPos(const Point& pos);
/// Find an element in this container and in its children by id /// Find an element in this container and in its children by id
UIElementPtr recursiveGetChildById(const std::string& id); UIElementPtr recursiveGetChildById(const std::string& id);
/// Pushs a child to the top
void pushChildToTop(const UIElementPtr& child);
int getChildCount() const { return m_children.size(); }
/// Disable all children except the specified element /// Disable all children except the specified element
bool lockElement(UIElementPtr element); bool lockElement(UIElementPtr element);

View File

@ -42,12 +42,21 @@ UIElement::UIElement(UI::EElementType type) :
void UIElement::destroy() void UIElement::destroy()
{ {
// we must always have a parent when destroying setVisible(false);
assert(getParent()); setEnabled(false);
// we cant delete now, as this call maybe in a event loop
g_dispatcher.addTask(boost::bind(&UIContainer::removeChild, getParent(), asUIContainer())); if(getParent()) {
// shared ptr must have 4 refs, (this + removeChild callback + parent + use_count call) // schedule removal from parent
assert(asUIElement().use_count() == 4); g_dispatcher.addTask(boost::bind(&UIContainer::removeChild, getParent(), asUIElement()));
}
// schedule internal destroy (used to check for leaks)
g_dispatcher.addTask(boost::bind(&UIElement::internalDestroy, asUIElement()));
}
void UIElement::internalDestroy()
{
// check for leaks, the number of references must be always 2 here
assert(asUIElement().use_count() == 2);
} }
void UIElement::setSkin(const UIElementSkinPtr& skin) void UIElement::setSkin(const UIElementSkinPtr& skin)

View File

@ -89,6 +89,8 @@ public:
friend class UIContainer; friend class UIContainer;
private: private:
void internalDestroy();
UI::EElementType m_type; UI::EElementType m_type;
UIContainerWeakPtr m_parent; UIContainerWeakPtr m_parent;
UIElementSkinPtr m_skin; UIElementSkinPtr m_skin;

View File

@ -50,6 +50,8 @@ void UIElementSkin::draw(UIElement *element)
ImagePtr UIElementSkin::loadImage(const YAML::Node& node) ImagePtr UIElementSkin::loadImage(const YAML::Node& node)
{ {
ImagePtr image; ImagePtr image;
TexturePtr texture;
if(node.FindValue("bordered image")) { if(node.FindValue("bordered image")) {
const YAML::Node& child = node["bordered image"]; const YAML::Node& child = node["bordered image"];
Rect left, right, top, bottom, topLeft, topRight, bottomLeft, bottomRight, center; Rect left, right, top, bottom, topLeft, topRight, bottomLeft, bottomRight, center;
@ -72,7 +74,6 @@ ImagePtr UIElementSkin::loadImage(const YAML::Node& node)
if(child.FindValue("center")) if(child.FindValue("center"))
child["center"] >> center; child["center"] >> center;
TexturePtr texture;
if(child.FindValue("image")) { if(child.FindValue("image")) {
std::string textureName; std::string textureName;
child["image"] >> textureName; child["image"] >> textureName;
@ -81,17 +82,34 @@ ImagePtr UIElementSkin::loadImage(const YAML::Node& node)
texture = g_uiSkins.getDefaultTexture(); texture = g_uiSkins.getDefaultTexture();
} }
image = ImagePtr(new BorderedImage(texture, if(texture) {
left, image = ImagePtr(new BorderedImage(texture,
right, left,
top, right,
bottom, top,
topLeft, bottom,
topRight, topLeft,
bottomLeft, topRight,
bottomRight, bottomLeft,
center)); bottomRight,
center));
}
} else if(node.FindValue("image")) {
std::string textureName;
node["image"] >> textureName;
texture = g_textures.get(textureName);
if(texture) {
image = ImagePtr(new Image(texture));
}
} }
if(texture && node.FindValue("antialised")){
bool antialised;
node["antialised"] >> antialised;
if(antialised)
texture->enableBilinearFilter();
}
return image; return image;
} }

View File

@ -37,6 +37,7 @@ public:
UIElementSkin(const std::string& name, UI::EElementType elementType) : UIElementSkin(const std::string& name, UI::EElementType elementType) :
m_name(name), m_name(name),
m_elementType(elementType) { } m_elementType(elementType) { }
UIElementSkin() : m_elementType(UI::Element) { }
virtual ~UIElementSkin() { } virtual ~UIElementSkin() { }
/// Load the skin from a YAML node /// Load the skin from a YAML node

View File

@ -133,8 +133,8 @@ void UILayout::recalculateLayout()
m_rect.moveVerticalCenter(m_anchors[ANCHOR_VERTICAL_CENTER].getPos() + m_marginTop - m_marginBottom); m_rect.moveVerticalCenter(m_anchors[ANCHOR_VERTICAL_CENTER].getPos() + m_marginTop - m_marginBottom);
} else { } else {
if(m_anchors[ANCHOR_TOP].isValid() && m_anchors[ANCHOR_BOTTOM].isValid()) { if(m_anchors[ANCHOR_TOP].isValid() && m_anchors[ANCHOR_BOTTOM].isValid()) {
m_rect.setLeft(m_anchors[ANCHOR_TOP].getPos() + m_marginTop); m_rect.setTop(m_anchors[ANCHOR_TOP].getPos() + m_marginTop);
m_rect.setRight(m_anchors[ANCHOR_BOTTOM].getPos() - m_marginBottom); m_rect.setBottom(m_anchors[ANCHOR_BOTTOM].getPos() - m_marginBottom);
} else if(m_anchors[ANCHOR_TOP].isValid()) { } else if(m_anchors[ANCHOR_TOP].isValid()) {
m_rect.moveTop(m_anchors[ANCHOR_TOP].getPos() + m_marginTop); m_rect.moveTop(m_anchors[ANCHOR_TOP].getPos() + m_marginTop);
} else if(m_anchors[ANCHOR_BOTTOM].isValid()) { } else if(m_anchors[ANCHOR_BOTTOM].isValid()) {

View File

@ -67,7 +67,7 @@ UIElementPtr UILoader::loadFile(const std::string& file, const UIContainerPtr& p
{ {
std::string fileContents = g_resources.loadTextFile(file); std::string fileContents = g_resources.loadTextFile(file);
if(!fileContents.size()) { if(!fileContents.size()) {
logFatal("Could not load ui file \"%s", file.c_str()); logError("Could not load ui file \"%s", file.c_str());
return UIElementPtr(); return UIElementPtr();
} }
@ -101,7 +101,7 @@ UIElementPtr UILoader::loadFile(const std::string& file, const UIContainerPtr& p
return element; return element;
} catch (YAML::Exception& e) { } catch (YAML::Exception& e) {
logFatal("Failed to load ui file \"%s\":\n %s", file.c_str(), e.what()); logError("Failed to load ui file \"%s\":\n %s", file.c_str(), e.what());
} }
return UIElementPtr(); return UIElementPtr();
@ -168,9 +168,15 @@ void UILoader::loadElement(const UIElementPtr& element, const YAML::Node& node)
} }
// set element skin // set element skin
if(node.FindValue("skin")) if(node.FindValue("skin")) {
element->setSkin(g_uiSkins.getElementSkin(element->getElementType(), node["skin"])); if(node["skin"].GetType() == YAML::CT_SCALAR) {
else // apply default skin element->setSkin(g_uiSkins.getElementSkin(element->getElementType(), node["skin"]));
} else {
UIElementSkinPtr skin = UIElementSkinPtr(new UIElementSkin());
skin->load(node["skin"]);
element->setSkin(skin);
}
} else // apply default skin
element->setSkin(g_uiSkins.getElementSkin(element->getElementType(), "default")); element->setSkin(g_uiSkins.getElementSkin(element->getElementType(), "default"));
// load elements common proprieties // load elements common proprieties
@ -252,6 +258,8 @@ void UILoader::loadElementAnchor(const UIElementPtr& element, EAnchorType type,
UILayoutPtr relativeElement; UILayoutPtr relativeElement;
if(relativeElementId == "parent" && element->getParent()) { if(relativeElementId == "parent" && element->getParent()) {
relativeElement = element->getParent()->asUILayout(); relativeElement = element->getParent()->asUILayout();
} else if(relativeElementId == "root") {
relativeElement = UIContainer::getRootContainer();
} else { } else {
UIElementPtr tmp = element->backwardsGetElementById(relativeElementId); UIElementPtr tmp = element->backwardsGetElementById(relativeElementId);
if(tmp) if(tmp)
@ -277,6 +285,8 @@ void UILoader::loadButton(const UIButtonPtr& button, const YAML::Node& node)
g_lua.pushClassInstance(button); g_lua.pushClassInstance(button);
g_lua.pushFunction(funcRef); g_lua.pushFunction(funcRef);
g_lua.lua_UIButton_setOnClick(); g_lua.lua_UIButton_setOnClick();
} else {
throw YAML::Exception(node["onClick"].GetMark(), "failed to parse lua script");
} }
} }
} }

View File

@ -42,6 +42,8 @@ public:
virtual const char *getScriptableName() const { return "UIWindow"; } virtual const char *getScriptableName() const { return "UIWindow"; }
virtual bool isFocusable() const { return true; }
private: private:
std::string m_title; std::string m_title;
bool m_moving; bool m_moving;

View File

@ -29,9 +29,8 @@
#include <core/platform.h> #include <core/platform.h>
#include <core/dispatcher.h> #include <core/dispatcher.h>
#include <ui/uiskins.h> #include <ui/uiskins.h>
#include "menustate.h"
#include "teststate.h"
#include <script/luascript.h> #include <script/luascript.h>
#include <ui/uicontainer.h>
/// Catches signals so we can exit nicely /// Catches signals so we can exit nicely
void signal_handler(int sig) void signal_handler(int sig)
@ -43,7 +42,7 @@ void signal_handler(int sig)
static bool stopping = false; static bool stopping = false;
if(!stopping) { if(!stopping) {
stopping = true; stopping = true;
g_engine.stop(); g_engine.onClose();
} }
break; break;
} }
@ -113,26 +112,30 @@ int main(int argc, const char *argv[])
// init engine // init engine
g_engine.init(); g_engine.init();
g_engine.enableFpsCounter();
// load ui skins
g_uiSkins.load("skins/tibiaskin.yml"); g_uiSkins.load("skins/tibiaskin.yml");
// state scope // load script modules
{ g_lua.loadAllModules();
boost::scoped_ptr<MenuState> initialState(new MenuState);
//boost::scoped_ptr<TestState> initialState(new TestState);
g_dispatcher.addTask(boost::bind(&Engine::changeState, &g_engine, initialState.get()));
Platform::showWindow(); if(!UIContainer::getRootContainer()->getChildCount())
//Platform::hideMouseCursor(); logFatal("no ui loaded at all, no reason to continue running");
g_engine.enableFpsCounter();
// main loop, run everything Platform::showWindow();
g_engine.run(); //Platform::hideMouseCursor();
// terminate stuff // main loop, run everything
g_engine.terminate(); g_engine.run();
g_uiSkins.terminate(); // poll remaning events
} g_engine.poll();
// terminate stuff
g_engine.terminate();
g_uiSkins.terminate();
// save configurations before exiting // save configurations before exiting
saveConfigs(); saveConfigs();

View File

@ -1,79 +0,0 @@
/* 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 <prerequisites.h>
#include <core/engine.h>
#include <core/dispatcher.h>
#include <graphics/framebuffer.h>
#include <graphics/graphics.h>
#include <graphics/textures.h>
#include <graphics/borderedimage.h>
#include <graphics/fonts.h>
#include <ui/ui.h>
#include "menustate.h"
#include <script/luascript.h>
void MenuState::onEnter()
{
m_background = g_textures.get("background.png");
m_background->enableBilinearFilter();
g_lua.loadFile("modules/mainmenu/mainmenu.lua");
}
void MenuState::onLeave()
{
}
void MenuState::onClose()
{
g_engine.stop();
}
bool MenuState::onInputEvent(const InputEvent& event)
{
return false;
}
void MenuState::onResize(const Size& size)
{
}
void MenuState::render()
{
// render background
static Size minTexCoordsSize(1240, 880);
const Size& screenSize = g_graphics.getScreenSize();
const Size& texSize = m_background->getSize();
Size texCoordsSize = screenSize;
if(texCoordsSize < minTexCoordsSize)
texCoordsSize.scale(minTexCoordsSize, KEEP_ASPECT_RATIO_BY_EXPANDING);
texCoordsSize = texCoordsSize.boundedTo(texSize);
Rect texCoords(0, 0, texCoordsSize);
texCoords.moveBottomRight(texSize.toPoint());
g_graphics.drawTexturedRect(Rect(0, 0, screenSize), m_background, texCoords);
}

View File

@ -1,59 +0,0 @@
/* 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 MENUSTATE_H
#define MENUSTATE_H
#include <prerequisites.h>
#include <core/gamestate.h>
#include <graphics/texture.h>
#include "protocollogin.h"
class MenuState : public GameState
{
public:
MenuState() { }
void onEnter();
void onLeave();
void onClose();
bool onInputEvent(const InputEvent& event);
void onResize(const Size& size);
void render();
private:
void enterGameButton_clicked();
void infoButton_clicked();
void optionsButton_clicked();
void enterGameWindowOkButton_clicked();
TexturePtr m_background;
ProtocolLoginPtr m_protocolLogin;
};
#endif // MENUSTATE_H