Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/ceguilua/ceguilua-0.5.0/ceguilua/CEGUILuaFunctor.cpp @ 2710

Last change on this file since 2710 was 2710, checked in by rgrieder, 15 years ago

Merged buildsystem3 containing buildsystem2 containing Adi's buildsystem branch back to the trunk.
Please update the media directory if you were not using buildsystem3 before.

  • Property svn:eol-style set to native
File size: 8.7 KB
Line 
1/***********************************************************************
2    filename: CEGUILuaFunctor.cpp
3    created:  Thu Jan 26 2006
4    author:   Tomas Lindquist Olsen <tomas@famolsen.dk>
5
6    purpose:  Implementation for LuaFunctor class
7*************************************************************************/
8/***************************************************************************
9 *   Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
10 *
11 *   Permission is hereby granted, free of charge, to any person obtaining
12 *   a copy of this software and associated documentation files (the
13 *   "Software"), to deal in the Software without restriction, including
14 *   without limitation the rights to use, copy, modify, merge, publish,
15 *   distribute, sublicense, and/or sell copies of the Software, and to
16 *   permit persons to whom the Software is furnished to do so, subject to
17 *   the following conditions:
18 *
19 *   The above copyright notice and this permission notice shall be
20 *   included in all copies or substantial portions of the Software.
21 *
22 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
26 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 *   OTHER DEALINGS IN THE SOFTWARE.
29 ***************************************************************************/
30#include "CEGUILuaFunctor.h"
31#include "CEGUILogger.h"
32#include "CEGUIExceptions.h"
33#include "CEGUIPropertyHelper.h"
34
35// include Lua libs and tolua++
36extern "C" {
37#include "lua.h"
38#include "lualib.h"
39#include "lauxlib.h"
40}
41
42#include "tolua/tolua++.h"
43
44// Start of CEGUI namespace section
45namespace CEGUI
46{
47
48/*************************************************************************
49    Constructor
50*************************************************************************/
51LuaFunctor::LuaFunctor(lua_State* state, int func, int selfIndex) :
52    L(state),
53    index(func),
54    self(selfIndex),
55    needs_lookup(false)
56{
57}
58
59/*************************************************************************
60    Constructor
61*************************************************************************/
62LuaFunctor::LuaFunctor(lua_State* state, const String& func, int selfIndex) :
63    L(state),
64    index(LUA_NOREF),
65    self(selfIndex),
66    needs_lookup(true),
67    function_name(func)
68{
69}
70
71/*************************************************************************
72    Constructor
73*************************************************************************/
74LuaFunctor::LuaFunctor(const LuaFunctor& cp) :
75    L(cp.L),
76    index(cp.index),
77    self(cp.self),
78    needs_lookup(cp.needs_lookup),
79    function_name(cp.function_name)
80{
81}
82
83/*************************************************************************
84    Destructor
85*************************************************************************/
86LuaFunctor::~LuaFunctor()
87{
88    if (self!=LUA_NOREF)
89    {
90        luaL_unref(L, LUA_REGISTRYINDEX, self);
91    }
92    if (index!=LUA_NOREF)
93    {
94        luaL_unref(L, LUA_REGISTRYINDEX, index);
95    }
96}
97
98/*************************************************************************
99    Call operator
100*************************************************************************/
101bool LuaFunctor::operator()(const EventArgs& args) const
102{
103    // is this a late binding?
104    if (needs_lookup)
105    {
106        pushNamedFunction(L, function_name);
107        // reference function
108        index = luaL_ref(L, LUA_REGISTRYINDEX);
109        needs_lookup = false;
110        CEGUI_LOGINSANE("Late binding of callback '"+function_name+"' performed");
111        function_name.clear();
112    }
113
114    // retrieve function
115    lua_rawgeti(L, LUA_REGISTRYINDEX, index);
116
117    // possibly self as well?
118    int nargs = 1;
119    if (self != LUA_NOREF)
120    {
121        lua_rawgeti(L, LUA_REGISTRYINDEX, self);
122        ++nargs;
123    }
124
125    // push EventArgs  parameter
126    tolua_pushusertype(L, (void*)&args, "const CEGUI::EventArgs");
127
128    // call it
129    int error = lua_pcall(L, nargs, 0, 0);
130
131    // handle errors
132    if (error)
133    {
134        String errStr(lua_tostring(L, -1));
135        lua_pop(L, 1);
136        throw ScriptException("Unable to call Lua event handler:\n\n"+errStr+"\n");
137    }
138
139    return true;
140}
141
142/*************************************************************************
143    do event subscription by reference instead of by name
144*************************************************************************/
145Event::Connection LuaFunctor::SubscribeEvent(EventSet* self, const String& event_name, int funcIndex, int selfIndex, lua_State* L)
146{
147    // should we pass a self to the callback?
148    int thisIndex = LUA_NOREF;
149    if (selfIndex != LUA_NOREF)
150    {
151        // reference self
152        thisIndex = luaL_ref(L, LUA_REGISTRYINDEX);
153    }
154
155    // do the real subscription
156    int type = lua_type(L,-1);
157    Event::Connection con;
158    if (type == LUA_TFUNCTION)
159    {
160        // reference function
161        int index = luaL_ref(L, LUA_REGISTRYINDEX);
162        LuaFunctor functor(L,index,thisIndex);
163        con = self->subscribeEvent(String(event_name), Event::Subscriber(functor));
164        // make sure we don't release the reference(s) we just made when this call returns
165        functor.index = LUA_NOREF;
166        functor.self = LUA_NOREF;
167    }
168    else if (type == LUA_TSTRING)
169    {
170        const char* str = lua_tostring(L, -1);
171        LuaFunctor functor(L,String(str),thisIndex);
172        con = self->subscribeEvent(String(event_name), Event::Subscriber(functor));
173        // make sure we don't release the reference we just (maybe) made when this call returns
174        functor.self = LUA_NOREF;
175    }
176    else
177    {
178        luaL_error(L,"bad function passed to subscribe function. must be a real function, or a string for late binding");
179    }
180
181    // return the event connection
182    return con;
183}
184
185/*************************************************************************
186    Pushes a named function on the stack
187*************************************************************************/
188void LuaFunctor::pushNamedFunction(lua_State* L, const String& handler_name)
189{
190    int top = lua_gettop(L);
191
192    // do we have any dots in the handler name? if so we grab the function as a table field
193    String::size_type i = handler_name.find_first_of((utf32)'.');
194    if (i!=String::npos)
195    {
196        // split the rest of the string up in parts seperated by '.'
197        // TODO: count the dots and size the vector accordingly from the beginning.
198        std::vector<String> parts;
199        String::size_type start = 0;
200        do
201        {
202            parts.push_back(handler_name.substr(start,i-start));
203            start = i+1;
204            i = handler_name.find_first_of((utf32)'.',start);
205        } while(i!=String::npos);
206
207        // add last part
208        parts.push_back(handler_name.substr(start));
209
210        // first part is the global
211        lua_getglobal(L, parts[0].c_str());
212        if (!lua_istable(L,-1))
213        {
214            lua_settop(L,top);
215            throw ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as first part is not a table");
216        }
217
218        // if there is more than two parts, we have more tables to go through
219        std::vector<String>::size_type visz = parts.size();
220        if (visz-- > 2) // avoid subtracting one later on
221        {
222            // go through all the remaining parts to (hopefully) have a valid Lua function in the end
223            std::vector<String>::size_type vi = 1;
224            while (vi<visz)
225            {
226                // push key, and get the next table
227                lua_pushstring(L,parts[vi].c_str());
228                lua_gettable(L,-2);
229                if (!lua_istable(L,-1))
230                {
231                    lua_settop(L,top);
232                    throw ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as part #"+PropertyHelper::uintToString(uint(vi+1))+" ("+parts[vi]+") is not a table");
233                }
234                // get rid of the last table and move on
235                lua_remove(L,-2);
236                vi++;
237            }
238        }
239
240        // now we are ready to get the function to call ... phew :)
241        lua_pushstring(L,parts[visz].c_str());
242        lua_gettable(L,-2);
243        lua_remove(L,-2); // get rid of the table
244    }
245    // just a regular global function
246    else
247    {
248        lua_getglobal(L, handler_name.c_str());
249    }
250
251    // is it a function
252    if (!lua_isfunction(L,-1))
253    {
254        lua_settop(L,top);
255        throw ScriptException("The Lua event handler: '"+handler_name+"' does not represent a Lua function");
256    }
257}
258
259} // namespace CEGUI
Note: See TracBrowser for help on using the repository browser.