📄 ceguiluafunctor.cpp
字号:
/***********************************************************************
filename: CEGUILuaFunctor.cpp
created: Thu Jan 26 2006
author: Tomas Lindquist Olsen <tomas@famolsen.dk>
purpose: Implementation for LuaFunctor class
*************************************************************************/
/***************************************************************************
* Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
*
* 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 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 "CEGUILuaFunctor.h"
#include "CEGUILogger.h"
#include "CEGUIExceptions.h"
#include "CEGUIPropertyHelper.h"
// include Lua libs and tolua++
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
#include "tolua++.h"
// Start of CEGUI namespace section
namespace CEGUI
{
/*************************************************************************
Constructor
*************************************************************************/
LuaFunctor::LuaFunctor(lua_State* state, int func, int selfIndex) :
L(state),
index(func),
self(selfIndex),
needs_lookup(false)
{
}
/*************************************************************************
Constructor
*************************************************************************/
LuaFunctor::LuaFunctor(lua_State* state, const String& func, int selfIndex) :
L(state),
index(LUA_NOREF),
self(selfIndex),
needs_lookup(true),
function_name(func)
{
}
/*************************************************************************
Constructor
*************************************************************************/
LuaFunctor::LuaFunctor(const LuaFunctor& cp) :
L(cp.L),
index(cp.index),
self(cp.self),
needs_lookup(cp.needs_lookup),
function_name(cp.function_name)
{
}
/*************************************************************************
Destructor
*************************************************************************/
LuaFunctor::~LuaFunctor()
{
if (self!=LUA_NOREF)
{
luaL_unref(L, LUA_REGISTRYINDEX, self);
}
if (index!=LUA_NOREF)
{
luaL_unref(L, LUA_REGISTRYINDEX, index);
}
}
/*************************************************************************
Call operator
*************************************************************************/
bool LuaFunctor::operator()(const EventArgs& args) const
{
// is this a late binding?
if (needs_lookup)
{
pushNamedFunction(L, function_name);
// reference function
index = luaL_ref(L, LUA_REGISTRYINDEX);
needs_lookup = false;
CEGUI_LOGINSANE("Late binding of callback '"+function_name+"' performed");
function_name.clear();
}
// retrieve function
lua_rawgeti(L, LUA_REGISTRYINDEX, index);
// possibly self as well?
int nargs = 1;
if (self != LUA_NOREF)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, self);
++nargs;
}
// push EventArgs parameter
tolua_pushusertype(L, (void*)&args, "const CEGUI::EventArgs");
// call it
int error = lua_pcall(L, nargs, 0, 0);
// handle errors
if (error)
{
String errStr(lua_tostring(L, -1));
lua_pop(L, 1);
throw ScriptException("Unable to call Lua event handler:\n\n"+errStr+"\n");
}
return true;
}
/*************************************************************************
do event subscription by reference instead of by name
*************************************************************************/
Event::Connection LuaFunctor::SubscribeEvent(EventSet* self, const String& event_name, int funcIndex, int selfIndex, lua_State* L)
{
// should we pass a self to the callback?
int thisIndex = LUA_NOREF;
if (selfIndex != LUA_NOREF)
{
// reference self
thisIndex = luaL_ref(L, LUA_REGISTRYINDEX);
}
// do the real subscription
int type = lua_type(L,-1);
Event::Connection con;
if (type == LUA_TFUNCTION)
{
// reference function
int index = luaL_ref(L, LUA_REGISTRYINDEX);
LuaFunctor functor(L,index,thisIndex);
con = self->subscribeEvent(String(event_name), Event::Subscriber(functor));
// make sure we don't release the reference(s) we just made when this call returns
functor.index = LUA_NOREF;
functor.self = LUA_NOREF;
}
else if (type == LUA_TSTRING)
{
const char* str = lua_tostring(L, -1);
LuaFunctor functor(L,String(str),thisIndex);
con = self->subscribeEvent(String(event_name), Event::Subscriber(functor));
// make sure we don't release the reference we just (maybe) made when this call returns
functor.self = LUA_NOREF;
}
else
{
luaL_error(L,"bad function passed to subscribe function. must be a real function, or a string for late binding");
}
// return the event connection
return con;
}
/*************************************************************************
Pushes a named function on the stack
*************************************************************************/
void LuaFunctor::pushNamedFunction(lua_State* L, const String& handler_name)
{
int top = lua_gettop(L);
// do we have any dots in the handler name? if so we grab the function as a table field
String::size_type i = handler_name.find_first_of((utf32)'.');
if (i!=String::npos)
{
// split the rest of the string up in parts seperated by '.'
// TODO: count the dots and size the vector accordingly from the beginning.
std::vector<String> parts;
String::size_type start = 0;
do
{
parts.push_back(handler_name.substr(start,i-start));
start = i+1;
i = handler_name.find_first_of((utf32)'.',start);
} while(i!=String::npos);
// add last part
parts.push_back(handler_name.substr(start));
// first part is the global
lua_getglobal(L, parts[0].c_str());
if (!lua_istable(L,-1))
{
lua_settop(L,top);
throw ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as first part is not a table");
}
// if there is more than two parts, we have more tables to go through
std::vector<String>::size_type visz = parts.size();
if (visz-- > 2) // avoid subtracting one later on
{
// go through all the remaining parts to (hopefully) have a valid Lua function in the end
std::vector<String>::size_type vi = 1;
while (vi<visz)
{
// push key, and get the next table
lua_pushstring(L,parts[vi].c_str());
lua_gettable(L,-2);
if (!lua_istable(L,-1))
{
lua_settop(L,top);
throw ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as part #"+PropertyHelper::uintToString(uint(vi+1))+" ("+parts[vi]+") is not a table");
}
// get rid of the last table and move on
lua_remove(L,-2);
vi++;
}
}
// now we are ready to get the function to call ... phew :)
lua_pushstring(L,parts[visz].c_str());
lua_gettable(L,-2);
lua_remove(L,-2); // get rid of the table
}
// just a regular global function
else
{
lua_getglobal(L, handler_name.c_str());
}
// is it a function
if (!lua_isfunction(L,-1))
{
lua_settop(L,top);
throw ScriptException("The Lua event handler: '"+handler_name+"' does not represent a Lua function");
}
}
} // namespace CEGUI
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -