Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/ceguilua/ceguilua-0.6.1/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: 9.1 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    } // if (needs_lookup)
113
114        ScriptWindowHelper* helper = 0;
115        //Set a global for this window
116        if(args.d_hasWindow)
117        {
118                WindowEventArgs& we = (WindowEventArgs&)args;
119                helper = new ScriptWindowHelper(we.window);
120                tolua_pushusertype(L,(void*)helper,"CEGUI::ScriptWindowHelper");
121                lua_setglobal(L,"this");
122        }
123
124    // retrieve function
125    lua_rawgeti(L, LUA_REGISTRYINDEX, index);
126
127    // possibly self as well?
128    int nargs = 1;
129    if (self != LUA_NOREF)
130    {
131        lua_rawgeti(L, LUA_REGISTRYINDEX, self);
132        ++nargs;
133    }
134
135    // push EventArgs  parameter
136    tolua_pushusertype(L, (void*)&args, "const CEGUI::EventArgs");
137
138    // call it
139    int error = lua_pcall(L, nargs, 0, 0);
140
141    // handle errors
142    if (error)
143    {
144        String errStr(lua_tostring(L, -1));
145        lua_pop(L, 1);
146                if(helper)
147                {
148                        delete helper;
149                        helper = 0;
150                }
151        throw ScriptException("Unable to call Lua event handler:\n\n"+errStr+"\n");
152    } // if (error)
153
154        if(helper)
155        {
156                delete helper;
157                helper = 0;
158        }
159
160    return true;
161}
162
163/*************************************************************************
164    do event subscription by reference instead of by name
165*************************************************************************/
166Event::Connection LuaFunctor::SubscribeEvent(EventSet* self, const String& event_name, int funcIndex, int selfIndex, lua_State* L)
167{
168    // should we pass a self to the callback?
169    int thisIndex = LUA_NOREF;
170    if (selfIndex != LUA_NOREF)
171    {
172        // reference self
173        thisIndex = luaL_ref(L, LUA_REGISTRYINDEX);
174    }
175
176    // do the real subscription
177    int type = lua_type(L,-1);
178    Event::Connection con;
179    if (type == LUA_TFUNCTION)
180    {
181        // reference function
182        int index = luaL_ref(L, LUA_REGISTRYINDEX);
183        LuaFunctor functor(L,index,thisIndex);
184        con = self->subscribeEvent(String(event_name), Event::Subscriber(functor));
185        // make sure we don't release the reference(s) we just made when this call returns
186        functor.index = LUA_NOREF;
187        functor.self = LUA_NOREF;
188    }
189    else if (type == LUA_TSTRING)
190    {
191        const char* str = lua_tostring(L, -1);
192        LuaFunctor functor(L,String(str),thisIndex);
193        con = self->subscribeEvent(String(event_name), Event::Subscriber(functor));
194        // make sure we don't release the reference we just (maybe) made when this call returns
195        functor.self = LUA_NOREF;
196    }
197    else
198    {
199        luaL_error(L,"bad function passed to subscribe function. must be a real function, or a string for late binding");
200    }
201
202    // return the event connection
203    return con;
204}
205
206/*************************************************************************
207    Pushes a named function on the stack
208*************************************************************************/
209void LuaFunctor::pushNamedFunction(lua_State* L, const String& handler_name)
210{
211    int top = lua_gettop(L);
212
213    // do we have any dots in the handler name? if so we grab the function as a table field
214    String::size_type i = handler_name.find_first_of((utf32)'.');
215    if (i!=String::npos)
216    {
217        // split the rest of the string up in parts seperated by '.'
218        // TODO: count the dots and size the vector accordingly from the beginning.
219        std::vector<String> parts;
220        String::size_type start = 0;
221        do
222        {
223            parts.push_back(handler_name.substr(start,i-start));
224            start = i+1;
225            i = handler_name.find_first_of((utf32)'.',start);
226        } while(i!=String::npos);
227
228        // add last part
229        parts.push_back(handler_name.substr(start));
230
231        // first part is the global
232        lua_getglobal(L, parts[0].c_str());
233        if (!lua_istable(L,-1))
234        {
235            lua_settop(L,top);
236            throw ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as first part is not a table");
237        }
238
239        // if there is more than two parts, we have more tables to go through
240        std::vector<String>::size_type visz = parts.size();
241        if (visz-- > 2) // avoid subtracting one later on
242        {
243            // go through all the remaining parts to (hopefully) have a valid Lua function in the end
244            std::vector<String>::size_type vi = 1;
245            while (vi<visz)
246            {
247                // push key, and get the next table
248                lua_pushstring(L,parts[vi].c_str());
249                lua_gettable(L,-2);
250                if (!lua_istable(L,-1))
251                {
252                    lua_settop(L,top);
253                    throw ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as part #"+PropertyHelper::uintToString(uint(vi+1))+" ("+parts[vi]+") is not a table");
254                }
255                // get rid of the last table and move on
256                lua_remove(L,-2);
257                vi++;
258            }
259        }
260
261        // now we are ready to get the function to call ... phew :)
262        lua_pushstring(L,parts[visz].c_str());
263        lua_gettable(L,-2);
264        lua_remove(L,-2); // get rid of the table
265    }
266    // just a regular global function
267    else
268    {
269        lua_getglobal(L, handler_name.c_str());
270    }
271
272    // is it a function
273    if (!lua_isfunction(L,-1))
274    {
275        lua_settop(L,top);
276        throw ScriptException("The Lua event handler: '"+handler_name+"' does not represent a Lua function");
277    }
278}
279
280} // namespace CEGUI
Note: See TracBrowser for help on using the repository browser.